Mercurial > hg > thermostat-ng > agent
changeset 2687:48e1cf54c238
Make JvmInfo into its own backend
review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-May/023339.html
reviewed-by: ebaron
line wrap: on
line diff
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/VmBlacklist.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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; - -import com.redhat.thermostat.common.Filter; - -/** - * Maintains a list of JVM processes that Thermostat should not - * monitor. - */ -public interface VmBlacklist { - - /** - * Adds a {@link Filter} to the blacklist. Virtual machines whose - * main class match the filter will not be monitored. - * @param filter - a filter whose matching VMs should not be monitored - */ - void addVmFilter(Filter<String> filter); - - /** - * Removes a {@link Filter} from the blacklist. New virtual machines - * will no longer be tested against this filter for blacklisting. - * @param filter - a filter previously in the blacklist - */ - void removeVmFilter(Filter<String> filter); - - /** - * Returns whether the given virtual machine should be monitored - * by matching it against filters in the blacklist. If any filter - * matches, then this method will return true. - * @param mainClass - a class name to check against classes covered - * by this blacklist - * @return true if blacklisted, false otherwise - */ - boolean isBlacklisted(String mainClass); - -} -
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/VmStatusListener.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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; - -import com.redhat.thermostat.annotations.ExtensionPoint; - -/** - * A listener that is notified when a JVM starts or is stopped. - * <p> - * Register an instance of this class as an OSGi service, and it will be - * notified of all VM {@link Status} events. - */ -@ExtensionPoint -public interface VmStatusListener { - - enum Status { - - /** A VM has just started now */ - VM_STARTED, - - /** - * A delayed version of {@link #VM_STARTED}. A VM was started at some - * point in the past. The listener was not informed about it then - * (probably because the listener was not registered at the time), but - * is being informed about it now. - */ - VM_ACTIVE, - - /** A VM was stopped just now */ - VM_STOPPED, - } - - // TODO what other information other than vmId and pid may be useful for plugins? - - public void vmStatusChanged(Status newStatus, String vmId, int pid); - -} -
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/VmStatusListenerRegistrar.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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; - -import java.util.HashMap; -import java.util.Map; - -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceRegistration; - -/** - * Registers a {@link VmStatusListener} as an OSGi Service. - * <p> - * This is just a convenience wrapper over - * {@link BundleContext#registerService(String, Object, java.util.Dictionary)}. - * It does absolutely nothing special. - * - * @see VmStatusListener - */ -public class VmStatusListenerRegistrar { - - private final BundleContext context; - private final Map<VmStatusListener, ServiceRegistration> registrations = new HashMap<>(); - - public VmStatusListenerRegistrar(BundleContext context) { - this.context = context; - } - - public void register(VmStatusListener listener) { - registrations.put(listener, context.registerService(VmStatusListener.class.getName(), listener, null)); - } - - public void unregister(VmStatusListener listener) { - ServiceRegistration registration = registrations.remove(listener); - if (registration == null) { - throw new IllegalArgumentException("no listener found"); - } - - registration.unregister(); - } -} -
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java Thu Jun 08 20:16:03 2017 +0200 +++ b/agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java Fri Jun 09 16:38:44 2017 +0200 @@ -46,7 +46,6 @@ import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; -import com.redhat.thermostat.agent.VmBlacklist; import com.redhat.thermostat.agent.config.AgentConfigsUtils; import com.redhat.thermostat.agent.ipc.server.AgentIPCService; import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool; @@ -57,7 +56,7 @@ import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.shared.config.CommonPaths; import com.redhat.thermostat.shared.config.InvalidConfigurationException; -import com.redhat.thermostat.utils.management.internal.AgentProxyFilter; + import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolControl; import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolImpl; @@ -82,9 +81,9 @@ CommonPaths paths = context.getService(ref); try { AgentConfigsUtils.setConfigFiles(paths.getSystemAgentConfigurationFile(), paths.getUserAgentConfigurationFile()); - VmBlacklistImpl blacklist = new VmBlacklistImpl(); - blacklist.addVmFilter(new AgentProxyFilter()); - context.registerService(VmBlacklist.class, blacklist, null); +// VmBlacklistImpl blacklist = new VmBlacklistImpl(); +// blacklist.addVmFilter(new AgentProxyFilter()); +// context.registerService(VmBlacklist.class, blacklist, null); } catch (InvalidConfigurationException e) { logger.log(Level.SEVERE, "Failed to start agent services", e); }
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/internal/VmBlacklistImpl.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.internal; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -import com.redhat.thermostat.agent.VmBlacklist; -import com.redhat.thermostat.common.Filter; - -public class VmBlacklistImpl implements VmBlacklist { - - private final List<Filter<String>> filters; - - public VmBlacklistImpl() { - this.filters = new CopyOnWriteArrayList<>(); - } - - @Override - public void addVmFilter(Filter<String> filter) { - filters.add(filter); - } - - @Override - public void removeVmFilter(Filter<String> filter) { - filters.remove(filter); - } - - @Override - public boolean isBlacklisted(String mainClass) { - boolean result = false; - for (Filter<String> filter : filters) { - if (filter.matches(mainClass)) { - result = true; - } - } - return result; - } - -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/core/src/main/java/com/redhat/thermostat/backend/BackendException.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,60 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.backend; + +public class BackendException extends Exception { + + private static final long serialVersionUID = 5575912008800705065L; + + public BackendException() { + super(); + } + + public BackendException(String msg) { + super(msg); + } + + public BackendException(Throwable cause) { + super(cause); + } + + public BackendException(String msg, Throwable cause) { + super(msg, cause); + } + +} +
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/BaseBackend.java Thu Jun 08 20:16:03 2017 +0200 +++ b/agent/core/src/main/java/com/redhat/thermostat/backend/BaseBackend.java Fri Jun 09 16:38:44 2017 +0200 @@ -45,13 +45,18 @@ private String name, description, vendor, version; public BaseBackend(String name, String description, String vendor) { - this(name, description, vendor, false); + this(name, description, vendor, "0.1", false); } - public BaseBackend(String name, String description, String vendor, boolean observeNewJvm) { + public BaseBackend(String name, String description, String vendor, String version) { + this(name, description, vendor, version, false); + } + + public BaseBackend(String name, String description, String vendor, String version, boolean observeNewJvm) { this.name = Objects.requireNonNull(name); this.description = Objects.requireNonNull(description); this.vendor = Objects.requireNonNull(vendor); + this.version = Objects.requireNonNull(version); this.observeNewJvm = observeNewJvm; }
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/HostPollingBackend.java Thu Jun 08 20:16:03 2017 +0200 +++ b/agent/core/src/main/java/com/redhat/thermostat/backend/HostPollingBackend.java Fri Jun 09 16:38:44 2017 +0200 @@ -67,7 +67,7 @@ badActions = new HashMap<>(); } - final void doScheduledActions() { + final public void doScheduledActions() { for (HostPollingAction action : actions) { try { action.run(); @@ -118,6 +118,6 @@ } // Intentionally final do-nothing. - final void preActivate() {}; - final void postDeactivate() {}; + final public void preActivate() {}; + final public void postDeactivate() {}; }
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/PollingBackend.java Thu Jun 08 20:16:03 2017 +0200 +++ b/agent/core/src/main/java/com/redhat/thermostat/backend/PollingBackend.java Fri Jun 09 16:38:44 2017 +0200 @@ -50,7 +50,7 @@ * extend child classes {@link HostPollingBackend} * or {@link VmPollingBackend} as appropriate. */ -abstract class PollingBackend extends BaseBackend { +public abstract class PollingBackend extends BaseBackend { private static final Logger logger = LoggingUtils.getLogger(PollingBackend.class); static final long DEFAULT_INTERVAL = 1000; // TODO make this configurable. @@ -58,10 +58,10 @@ private ScheduledExecutorService executor; private boolean isActive; - PollingBackend(String name, String description, String vendor, + public PollingBackend(String name, String description, String vendor, Version version, ScheduledExecutorService executor) { - super(name, description, vendor, true); + super(name, description, vendor, version.getVersionNumber(), true); this.executor = executor; setVersion(version.getVersionNumber()); } @@ -107,14 +107,14 @@ } // Give child classes a chance to specify what should happen at each polling interval. - abstract void doScheduledActions(); + protected abstract void doScheduledActions(); // An opportunity for child classes to do some setup upon activation. // Will execute before any actions are scheduled. - void preActivate() {} + protected void preActivate() {} // An opportunity for child classes to do some cleanup upon deactivation. // Will execute after all actions are unscheduled. - void postDeactivate() {} + protected void postDeactivate() {} }
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/VmListenerBackend.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,187 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.agent.VmStatusListener; -import com.redhat.thermostat.agent.VmStatusListenerRegistrar; -import com.redhat.thermostat.backend.internal.BackendException; -import com.redhat.thermostat.backend.internal.VmMonitor; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.storage.core.WriterID; - -/** - * This class is a convenient subclass of {@link Backend} (via {@link BaseBackend}) for those - * that need to attach {@link VmUpdateListener} in response to starting and stopping of JVMs on a - * host. - * - * @see VmStatusListener - * @see Backend - * @see BaseBackend - */ -public abstract class VmListenerBackend extends BaseBackend implements VmStatusListener { - - private static final Logger logger = LoggingUtils.getLogger(VmListenerBackend.class); - - private WriterID writerId; - private VmStatusListenerRegistrar registrar; - private VmMonitor monitor; - private boolean started; - private boolean initialized; - - public VmListenerBackend(String backendName, String description, String vendor) { - this(backendName, description, vendor, false); - } - public VmListenerBackend(String backendName, String description, - String vendor, boolean observeNewJvm) { - super(backendName, description, vendor, observeNewJvm); - try { - this.monitor = new VmMonitor(); - } catch (BackendException e) { - logger.log(Level.SEVERE, "Unable to create backend", e); - } - } - - /** - * {@inheritDoc} - * - * <p> - * Registers a VmUpdateListener to begin receiving VM lifecycle events. - * Subclasses should call <code>super.activate()</code> when overriding this method. - * </p> - * <p> - * This {@link VmListenerBackend} should be initialized via - * {@link #initialize(WriterID, VmStatusListenerRegistrar)} before calling this method. - * </p> - */ - @Override - public boolean activate() { - if (!initialized) { - logger.warning("Backend not started, initialize must be called before activate"); - } else if (!started && monitor != null) { - registrar.register(this); - started = true; - } - return started; - } - - /** - * {@inheritDoc} - * - * <p> - * Unregisters the VmUpdateListener to stop receiving VM lifecycle events. - * Subclasses should call <code>super.deactivate()</code> when overriding this method. - * </p> - */ - @Override - public boolean deactivate() { - if (started && monitor != null) { - registrar.unregister(this); - monitor.removeVmListeners(); - started = false; - } - return !started; - } - - @Override - public boolean isActive() { - return started; - } - - public void vmStatusChanged(Status newStatus, String vmId, int pid) { - switch (newStatus) { - case VM_STARTED: - /* fall-through */ - case VM_ACTIVE: - if (getObserveNewJvm()) { - String wId = writerId.getWriterID(); - VmUpdateListener listener = null; - try { - listener = createVmListener(wId, vmId, pid); - } catch (Throwable t) { - logger.log(Level.INFO, "Creating the VM listener for a VmListenerBackend threw an exception. Going to ignore the backend!", t); - } - if (listener != null) { - monitor.handleNewVm(listener, pid); - } - } else { - logger.log(Level.FINE, "skipping new vm " + pid); - } - break; - case VM_STOPPED: - monitor.handleStoppedVm(pid); - break; - default: - break; - } - } - - /** - * Initializes this {@link VmListenerBackend} with necessary services. This method - * must be called before {@link #activate()}. - * @param writerId service uniquely identifying this agent - * @param registrar responsible for registering and unregistering instances of {@link VmStatusListener} - * @param version version number of this backend - */ - protected void initialize(WriterID writerId, VmStatusListenerRegistrar registrar, String version) { - this.writerId = writerId; - this.registrar = registrar; - setVersion(version); - this.initialized = true; - } - - /** - * Creates a new {@link VmUpdateListener} for the virtual machine - * specified by the pid. This method is called when a new - * JVM is started or for JVMs already active when this Backend - * was activated. - * @param vmId unique identifier of the JVM - * @param pid the process ID of the JVM - * @return a new listener for the VM specified by pid - */ - protected abstract VmUpdateListener createVmListener(String writerId, String vmId, int pid); - - /* - * For testing purposes only. - */ - void setMonitor(VmMonitor monitor) { - this.monitor = monitor; - } -} -
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/VmPollingAction.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend; - -/** - * An action to be performed at a regular interval as part of a - * {@link VmPollingBackend} implementation. - */ -public interface VmPollingAction { - - /** - * Run the action. - * - * @param vmId a String representation of the VmID on which to take action. - * @param pid the process ID of the JVM instance on which to take action. - */ - public void run(String vmId, int pid); - -}
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/VmPollingBackend.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,159 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend; - -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.ScheduledExecutorService; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.agent.VmStatusListener; -import com.redhat.thermostat.agent.VmStatusListenerRegistrar; -import com.redhat.thermostat.common.Pair; -import com.redhat.thermostat.common.Version; -import com.redhat.thermostat.common.utils.LoggingUtils; - -/** - * Convenience {@link Backend} class for implementations that will take some - * action for each monitored JVM process on a regular interval. Simply - * extend this class, implement any missing methods, and register one or - * more {@link VmPollingAction} implementations during instantiation. - */ -public abstract class VmPollingBackend extends PollingBackend implements VmStatusListener { - - private final Set<VmPollingAction> actions; - private final Map<String, Pair<Integer, VmPollingAction>> badActions; - private final Map<Integer, String> pidsToMonitor = new ConcurrentHashMap<>(); - private final VmStatusListenerRegistrar registrar; - private static final Logger logger = LoggingUtils.getLogger(VmPollingBackend.class); - private static final int EXCEPTIONS_THRESHOLD = 10; - - public VmPollingBackend(String name, String description, - String vendor, Version version, ScheduledExecutorService executor, - VmStatusListenerRegistrar registrar) { - super(name, description, vendor, version, executor); - this.registrar = registrar; - this.actions = new CopyOnWriteArraySet<>(); - this.badActions = new HashMap<>(); - } - - @Override - final void preActivate() { - registrar.register(this); - } - - @Override - final void postDeactivate() { - registrar.unregister(this); - } - - @Override - final void doScheduledActions() { - for (Entry<Integer, String> entry : pidsToMonitor.entrySet()) { - int pid = entry.getKey(); - String vmId = entry.getValue(); - for (VmPollingAction action : actions) { - try { - action.run(vmId, pid); - } catch (Throwable t) { - handleActionException(action, vmId); - } - } - } - } - - private synchronized void handleActionException(VmPollingAction action, String vmId) { - final String actionName = action.getClass().getName(); - final String actionKey = actionName + vmId; - Pair<Integer, VmPollingAction> actionPair = badActions.remove(actionKey); - if (actionPair == null) { - actionPair = new Pair<>(Integer.valueOf(1), action); - } - int exceptionsPerAction = actionPair.getFirst(); - if (exceptionsPerAction < EXCEPTIONS_THRESHOLD) { - exceptionsPerAction++; - logger.info(VmPollingAction.class.getSimpleName() + " " + - actionName + " threw an exception"); - badActions.put(actionKey, new Pair<>(exceptionsPerAction, action)); - } else { - logger.fine("Removing " + actionName + " due to too many repeated exceptions."); - unregisterAction(action); - } - } - - /** - * Register an action to be performed at each polling interval. It is - * recommended that implementations register all such actions during - * instantiation. - */ - protected final void registerAction(VmPollingAction action) { - actions.add(action); - } - - /** - * Unregister an action so that it will no longer be performed at each - * polling interval. If no such action has been registered, this - * method has no effect. Depending on thread timing issues, the action - * may be performed once even after this method has been called. - */ - protected final void unregisterAction(VmPollingAction action) { - actions.remove(action); - } - - @Override - public void vmStatusChanged(Status newStatus, String vmId, int pid) { - switch (newStatus) { - case VM_STARTED: - /* fall-through */ - case VM_ACTIVE: - if (getObserveNewJvm()) { - pidsToMonitor.put(pid, vmId); - } else { - logger.log(Level.FINE, "skipping new vm " + pid); - } - break; - case VM_STOPPED: - pidsToMonitor.remove(pid); - break; - } - } -}
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/VmUpdate.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend; - -/** - * This interface can be used to query the performance counters - * of a monitored JVM when they are updated. - * @see VmUpdateListener#countersUpdated(VmUpdate) - */ -public interface VmUpdate { - - /** - * Queries the specified JVM performance counter with a Long data type. - * @param name - The name of the performance counter - * @return The current value of the requested counter, or null if no - * such counter exists - * @throws VmUpdateException if there is a problem communicating with - * the JVM - * @throws ClassCastException if the value of the counter is not a Long - */ - Long getPerformanceCounterLong(String name) throws VmUpdateException; - - /** - * Queries the specified JVM performance counter with a String data type. - * @param name - The name of the performance counter - * @return The current value of the requested counter, or null if no - * such counter exists - * @throws VmUpdateException if there is a problem communicating with - * the JVM - * @throws ClassCastException if the value of the counter is not a String - */ - String getPerformanceCounterString(String name) throws VmUpdateException; - -} -
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/VmUpdateException.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend; - -/** - * Exception class indicating that a problem occurred accessing - * a monitored JVM's performance counters. - */ -public class VmUpdateException extends Exception { - - private static final long serialVersionUID = 7644805109896007513L; - - /** - * Constructs a VmUpdateException with no message. - */ - public VmUpdateException() { - super(); - } - - /** - * Constructs a VmUpdateException with an error message. - */ - public VmUpdateException(String msg) { - super(msg); - } - - /** - * Constructs a VmUpdateException with a cause. - */ - public VmUpdateException(Throwable cause) { - super(cause); - } - - /** - * Constructs a VmUpdateException with an error message and cause. - */ - public VmUpdateException(String msg, Throwable cause) { - super(msg, cause); - } - -} -
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/VmUpdateListener.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend; - -/** - * A listener that can be registered to receive updates for a - * JVM's performance counters. - * @see VmListenerBackend#createVmListener(int) - */ -public interface VmUpdateListener { - - /** - * This method is called when the performance counters - * are updated for the JVM this listener is attached to. - * @param update - object to query performance counter values - */ - public void countersUpdated(VmUpdate update); - -} -
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/internal/BackendException.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.internal; - -public class BackendException extends Exception { - - private static final long serialVersionUID = 5575912008800705065L; - - public BackendException() { - super(); - } - - public BackendException(String msg) { - super(msg); - } - - public BackendException(Throwable cause) { - super(cause); - } - - public BackendException(String msg, Throwable cause) { - super(msg, cause); - } - -} -
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/internal/VmListenerWrapper.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,126 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.internal; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.backend.VmUpdate; -import com.redhat.thermostat.backend.VmUpdateException; -import com.redhat.thermostat.backend.VmUpdateListener; -import com.redhat.thermostat.common.utils.LoggingUtils; - -import sun.jvmstat.monitor.Monitor; -import sun.jvmstat.monitor.MonitorException; -import sun.jvmstat.monitor.MonitoredVm; -import sun.jvmstat.monitor.event.MonitorStatusChangeEvent; -import sun.jvmstat.monitor.event.VmEvent; -import sun.jvmstat.monitor.event.VmListener; - -public class VmListenerWrapper implements VmListener { - - private static final Logger logger = LoggingUtils.getLogger(VmListenerWrapper.class); - // Threshold until this listener gets removed from the JVM in case of it throwing - // exceptions on countersUpdated() - private static final int EXCEPTION_THRESHOLD = 10; - private final VmUpdateListener listener; - private final MonitoredVm vm; - private final VmUpdate update; - private int exceptionCount; - - public VmListenerWrapper(VmUpdateListener listener, MonitoredVm vm) { - this.listener = listener; - this.vm = vm; - this.update = new VmUpdateImpl(this); - } - - @Override - public void monitorsUpdated(VmEvent event) { - if (!vm.equals(event.getMonitoredVm())) { - throw new AssertionError("Received change event for wrong VM"); - } - try { - listener.countersUpdated(update); - } catch (Throwable t) { - handleListenerException(t); - } - } - - private void handleListenerException(Throwable t) { - final String listenerName = listener.getClass().getName(); - if (exceptionCount < EXCEPTION_THRESHOLD) { - logger.log(Level.INFO, "VM listener " + listenerName + " threw an exception", t); - exceptionCount++; - } else { - logger.fine("Removing bad listener " + listenerName + " due to too many repeated exceptions."); - try { - vm.removeVmListener(this); - } catch (MonitorException e) { - // ignore remove failures for bad listeners - } - } - } - - @Override - public void monitorStatusChanged(MonitorStatusChangeEvent event) { - // Nothing to do here - } - - @Override - public void disconnected(VmEvent event) { - // Nothing to do here - } - - public Monitor getMonitor(String name) throws VmUpdateException { - Monitor result; - try { - result = vm.findByName(name); - } catch (MonitorException e) { - throw new VmUpdateException("Error communicating with monitored VM", e); - } - return result; - } - - /* - * For testing purposes only. - */ - VmUpdateListener getVmUpdateListener() { - return listener; - } - -} -
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/internal/VmMonitor.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.internal; - -import java.net.URISyntaxException; -import java.util.HashMap; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import sun.jvmstat.monitor.HostIdentifier; -import sun.jvmstat.monitor.MonitorException; -import sun.jvmstat.monitor.MonitoredHost; -import sun.jvmstat.monitor.MonitoredVm; -import sun.jvmstat.monitor.VmIdentifier; - -import com.redhat.thermostat.common.portability.ProcessChecker; -import com.redhat.thermostat.backend.VmUpdateListener; -import com.redhat.thermostat.common.Pair; -import com.redhat.thermostat.common.utils.LoggingUtils; - -public class VmMonitor { - - private final Logger logger = LoggingUtils.getLogger(VmMonitor.class); - - private final ProcessChecker processChecker; - private MonitoredHost host; - private Map<Integer, Pair<MonitoredVm, VmListenerWrapper>> pidToData = new HashMap<>(); - - public VmMonitor() throws BackendException { - this(new ProcessChecker()); - } - - public VmMonitor(ProcessChecker processChecker) throws BackendException { - this.processChecker = processChecker; - try { - HostIdentifier hostId = new HostIdentifier((String) null); - host = MonitoredHost.getMonitoredHost(hostId); - } catch (MonitorException me) { - throw new BackendException("Problems with connecting jvmstat to local machine", me); - } catch (URISyntaxException use) { - throw new BackendException("Failed to create host identifier", use); - } - } - - public void handleNewVm(VmUpdateListener listener, int pid) { - try { - MonitoredVm vm = host.getMonitoredVm(host.getHostIdentifier().resolve(new VmIdentifier(String.valueOf(pid)))); - VmListenerWrapper wrapper = new VmListenerWrapper(listener, vm); - vm.addVmListener(wrapper); - - pidToData.put(pid, new Pair<>(vm, wrapper)); - logger.finer("Attached " + listener.getClass().getName() + " for VM: " + pid); - } catch (MonitorException e) { - logMsg(pid, e); - } catch (URISyntaxException e) { - logger.log(Level.WARNING, "unable to attach to vm " + pid, e); - } - } - - private void logMsg(int pid, MonitorException e) { - Throwable cause = e.getCause(); - if (cause != null && cause instanceof IllegalArgumentException && !processChecker.exists(pid)) { - logger.log(Level.FINEST, "Tried to attach to a process which no longer exists. Pid was " + pid, e); - } else { - logger.log(Level.WARNING, "unable to attach to vm" + pid, e); - } - } - - public void handleStoppedVm(int pid) { - Pair<MonitoredVm, VmListenerWrapper> data = pidToData.remove(pid); - // we were not monitoring pid at all, so nothing to do - if (data == null) { - return; - } - - MonitoredVm vm = data.getFirst(); - VmListenerWrapper listener = data.getSecond(); - try { - vm.removeVmListener(listener); - } catch (MonitorException e) { - logger.log(Level.WARNING, "can't remove vm listener", e); - } - vm.detach(); - } - - public void removeVmListeners() { - for (Pair<MonitoredVm, VmListenerWrapper> data : pidToData.values()) { - MonitoredVm vm = data.getFirst(); - VmListenerWrapper listener = data.getSecond(); - try { - vm.removeVmListener(listener); - } catch (MonitorException e) { - logger.log(Level.WARNING, "can't remove vm listener", e); - } - } - pidToData.clear(); - } - - /* - * For testing purposes only. - */ - void setHost(MonitoredHost host) { - this.host = host; - } - - /* - * For testing purposes only. - */ - Map<Integer, Pair<MonitoredVm, VmListenerWrapper>> getPidToDataMap() { - return pidToData; - } - -} -
--- a/agent/core/src/main/java/com/redhat/thermostat/backend/internal/VmUpdateImpl.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.internal; - -import sun.jvmstat.monitor.Monitor; - -import com.redhat.thermostat.backend.VmUpdate; -import com.redhat.thermostat.backend.VmUpdateException; - - -public class VmUpdateImpl implements VmUpdate { - - private VmListenerWrapper wrapper; - - VmUpdateImpl(VmListenerWrapper wrapper) { - this.wrapper = wrapper; - } - - @Override - public Long getPerformanceCounterLong(String name) throws VmUpdateException { - return (Long) getPerformanceCounter(name); - } - - @Override - public String getPerformanceCounterString(String name) - throws VmUpdateException { - return (String) getPerformanceCounter(name); - } - - private Object getPerformanceCounter(String name) throws VmUpdateException { - Object result = null; - Monitor monitor = wrapper.getMonitor(name); - if (monitor != null) { - result = monitor.getValue(); - } - return result; - } - - /* - * For testing purposes only. - */ - VmListenerWrapper getWrapper() { - return wrapper; - } - -} -
--- a/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/AgentProxyFilter.java Thu Jun 08 20:16:03 2017 +0200 +++ b/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/AgentProxyFilter.java Fri Jun 09 16:38:44 2017 +0200 @@ -37,11 +37,15 @@ package com.redhat.thermostat.utils.management.internal; import com.redhat.thermostat.common.Filter; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Service; /** * Prevents Agent Proxies from being monitored, which would create * an infinite chain of agent proxies being created. */ +@Component +@Service(value = AgentProxyFilter.class) public class AgentProxyFilter extends Filter<String> { private static final String AGENT_PROXY_CLASS = "com.redhat.thermostat.agent.proxy.server.AgentProxy";
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/VmStatusListenerRegistrarTest.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - -import org.junit.Test; - -import com.redhat.thermostat.agent.VmStatusListener; -import com.redhat.thermostat.agent.VmStatusListenerRegistrar; -import com.redhat.thermostat.testutils.StubBundleContext; - -public class VmStatusListenerRegistrarTest { - - @Test - public void testRegister() { - StubBundleContext context = new StubBundleContext(); - VmStatusListener listener = mock(VmStatusListener.class); - - VmStatusListenerRegistrar registerer = new VmStatusListenerRegistrar(context); - registerer.register(listener); - - assertTrue(context.isServiceRegistered(VmStatusListener.class.getName(), listener.getClass())); - assertEquals(1, context.getAllServices().size()); - } - - @Test - public void testUnregister() { - StubBundleContext context = new StubBundleContext(); - VmStatusListener listener = mock(VmStatusListener.class); - - VmStatusListenerRegistrar registerer = new VmStatusListenerRegistrar(context); - registerer.register(listener); - registerer.unregister(listener); - - assertFalse(context.isServiceRegistered(VmStatusListener.class.getName(), listener.getClass())); - assertEquals(0, context.getAllServices().size()); - } -} -
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java Thu Jun 08 20:16:03 2017 +0200 +++ b/agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -49,7 +49,6 @@ import org.junit.Test; import org.osgi.framework.ServiceRegistration; -import com.redhat.thermostat.agent.VmBlacklist; import com.redhat.thermostat.agent.ipc.server.AgentIPCService; import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool; import com.redhat.thermostat.shared.config.CommonPaths; @@ -88,7 +87,6 @@ assertTrue(context.isServiceRegistered(MXBeanConnectionPool.class.getName(), MXBeanConnectionPoolImpl.class)); assertTrue(context.isServiceRegistered(MXBeanConnectionPoolControl.class.getName(), MXBeanConnectionPoolImpl.class)); - assertTrue(context.isServiceRegistered(VmBlacklist.class.getName(), VmBlacklistImpl.class)); } @Test
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/BaseBackendTest.java Thu Jun 08 20:16:03 2017 +0200 +++ b/agent/core/src/test/java/com/redhat/thermostat/backend/BaseBackendTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -134,13 +134,13 @@ public TestBaseBackend(String name, String description, String vendor, String version) { - super(name, description, vendor); + super(name, description, vendor, "1.0"); setVersion(version); } public TestBaseBackend(String name, String description, String vendor, String version, boolean observeNewJvm) { - super(name, description, vendor, observeNewJvm); + super(name, description, vendor, "1.0", observeNewJvm); setVersion(version); }
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/PollingBackendTest.java Thu Jun 08 20:16:03 2017 +0200 +++ b/agent/core/src/test/java/com/redhat/thermostat/backend/PollingBackendTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -74,17 +74,17 @@ } @Override - void doScheduledActions() { + protected void doScheduledActions() { // Won't be called because mock executor. } @Override - void preActivate() { + protected void preActivate() { mockActivate.activate(); } @Override - void postDeactivate() { + protected void postDeactivate() { mockActivate.deactivate(); }}; } @@ -140,7 +140,7 @@ } @Override - void doScheduledActions() { + protected void doScheduledActions() { mockAction.doAction(); }}; backend.activate(); @@ -156,11 +156,11 @@ } private interface CustomActivateTester { - public void activate(); - public void deactivate(); + void activate(); + void deactivate(); } private interface ScheduledActionTester { - public void doAction(); + void doAction(); } }
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/VmListenerBackendTest.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,231 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.net.URISyntaxException; - -import org.junit.Before; -import org.junit.Test; - -import sun.jvmstat.monitor.MonitorException; - -import com.redhat.thermostat.agent.VmStatusListener.Status; -import com.redhat.thermostat.agent.VmStatusListenerRegistrar; -import com.redhat.thermostat.backend.internal.VmMonitor; -import com.redhat.thermostat.common.internal.test.Bug; -import com.redhat.thermostat.storage.core.WriterID; - -public class VmListenerBackendTest { - private static final String VERSION = "0.0.0"; - private static final String VM_ID = "vmId"; - private static final int VM_PID = 1; - - private VmListenerBackend backend; - private VmStatusListenerRegistrar registrar; - private VmMonitor monitor; - private VmUpdateListener listener; - private WriterID writerId; - - @Before - public void setup() { - registrar = mock(VmStatusListenerRegistrar.class); - writerId = mock(WriterID.class); - backend = new TestBackend("Test Backend", "Backend for test", "Test Co."); - monitor = mock(VmMonitor.class); - listener = mock(VmUpdateListener.class); - backend.setMonitor(monitor); - } - - @Test - public void testActivate() { - backend.initialize(writerId, registrar, VERSION); - backend.activate(); - assertTrue(backend.isActive()); - verify(registrar).register(backend); - } - - @Test - public void testActivateNoInit() { - backend.activate(); - assertFalse(backend.isActive()); - verify(registrar, never()).register(backend); - } - - @Test - public void testActivateTwice() { - backend.initialize(writerId, registrar, VERSION); - assertTrue(backend.activate()); - assertTrue(backend.isActive()); - - assertTrue(backend.activate()); - assertTrue(backend.isActive()); - } - - @Test - public void testCanNotActivateWithoutMonitor() { - backend.initialize(writerId, registrar, VERSION); - backend.setMonitor(null); - - assertFalse(backend.activate()); - assertFalse(backend.isActive()); - } - - @Test - public void testDeactivate() { - backend.initialize(writerId, registrar, VERSION); - backend.activate(); - backend.deactivate(); - verify(registrar).unregister(backend); - assertFalse(backend.isActive()); - } - - @Test - public void testDeactivateTwice() { - backend.initialize(writerId, registrar, VERSION); - backend.activate(); - - assertTrue(backend.deactivate()); - assertFalse(backend.isActive()); - assertTrue(backend.deactivate()); - } - - @Test - public void testNewVM() { - backend.initialize(writerId, registrar, VERSION); - // Should be no response if not observing new jvm. - backend.setObserveNewJvm(false); - backend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID); - verify(monitor, times(0)).handleNewVm(same(listener), same(VM_PID)); - - backend.setObserveNewJvm(true); - backend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID); - verify(monitor).handleNewVm(listener, VM_PID); - } - - /** - * createVmListener() might be plugin-supplied code. When creating the - * listener fails due to exceptions, other listeners should still continue - * to work. That is, the exception of creating one listener must not be - * propagated. - */ - @Bug(id = "3242", - summary = "Adverse Backend breaks other Backends badly ", - url = "http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=3242") - @Test - public void testNewVMCreateListenerWithExceptions() { - VmListenerBackend testBackend = new ExceptionThrowingCreateVmListenerBackend( - "Test Backend", "Backend for test", "Test Co.", VERSION); - testBackend.initialize(writerId, registrar, VERSION); - testBackend.setObserveNewJvm(true); - VmMonitor testMonitor = mock(VmMonitor.class); - testBackend.setMonitor(testMonitor); - testBackend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID); - verify(testMonitor, times(0)).handleNewVm(any(VmUpdateListener.class), any(int.class)); - } - - @Test - public void testAlreadyRunningVM() { - backend.initialize(writerId, registrar, VERSION); - backend.setObserveNewJvm(true); - backend.vmStatusChanged(Status.VM_ACTIVE, VM_ID, VM_PID); - - verify(monitor).handleNewVm(listener, VM_PID); - } - - @Test - public void testStoppedVM() throws MonitorException, URISyntaxException { - backend.initialize(writerId, registrar, VERSION); - backend.setObserveNewJvm(true); - backend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID); - backend.vmStatusChanged(Status.VM_STOPPED, VM_ID, VM_PID); - - verify(monitor).handleStoppedVm(VM_PID); - } - - @Test - public void testDeactivateUnregistersListener() throws URISyntaxException, MonitorException { - backend.initialize(writerId, registrar, VERSION); - backend.activate(); - - backend.setObserveNewJvm(true); - backend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID); - backend.deactivate(); - verify(monitor).removeVmListeners(); - } - - private class TestBackend extends VmListenerBackend { - - public TestBackend(String name, String description, String vendor) { - super(name, description, vendor); - } - - @Override - public int getOrderValue() { - return 0; - } - - @Override - protected VmUpdateListener createVmListener(String writerId, String vmId, int pid) { - return listener; - } - - } - - private class ExceptionThrowingCreateVmListenerBackend extends TestBackend { - - public ExceptionThrowingCreateVmListenerBackend(String name, String description, String vendor, - String version) { - super(name, description, vendor); - } - - @Override - protected VmUpdateListener createVmListener(String writerId, String vmId, int pid) { - throw new RuntimeException("createVmListener() testing!"); - } - } - -} -
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/VmPollingBackendTest.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,275 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ScheduledExecutorService; - -import org.junit.Before; -import org.junit.Test; - -import com.redhat.thermostat.agent.VmStatusListener.Status; -import com.redhat.thermostat.agent.VmStatusListenerRegistrar; -import com.redhat.thermostat.common.Version; -import com.redhat.thermostat.common.internal.test.Bug; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class VmPollingBackendTest { - - private VmPollingBackend backend; - private ScheduledExecutorService mockExecutor; - private VmStatusListenerRegistrar mockRegistrar; - - @Before - public void setUp() { - mockExecutor = mock(ScheduledExecutorService.class); - Version mockVersion = mock(Version.class); - when(mockVersion.getVersionNumber()).thenReturn("backend-version"); - mockRegistrar = mock(VmStatusListenerRegistrar.class); - backend = new VmPollingBackend("backend-name", "backend-description", - "backend-vendor", mockVersion, mockExecutor, mockRegistrar) { - @Override - public int getOrderValue() { - return 0; // Doesn't matter, not being tested. - } - }; - if (!backend.getObserveNewJvm()) { - /* At time of writing, default is true. This is - * inherited from parent PollingBackend. In case - * default changes: - */ - backend.setObserveNewJvm(true); - } - } - - /** - * If an action throws exceptions repeatedly, that action shall get - * disabled/unregistered. - */ - @Bug(id = "3242", - summary = "Adverse Backend breaks other Backends badly ", - url = "http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=3242") - @Test - public void testDoScheduledActionsWithExceptions() { - final int beyondExceptionThreshold = 13; // anything beyond 10 will do - String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2"; - int pid1 = 123, pid2 = 456; - backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1); - backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2); - BadVmPollingAction badAction = new BadVmPollingAction(); - backend.registerAction(badAction); - for (int i = 0; i < beyondExceptionThreshold; i++) { - backend.doScheduledActions(); - } - - // The exceptions thrown for one vmID might disable the action - // for *all* other vmIDs too. So the call count for one of the - // vmIDs is actually 9, whereas the other one must have reached - // the threshold count of 10. - int callCountVm1 = badAction.getCallCount(vmId1); - int callCountVm2 = badAction.getCallCount(vmId2); - int minCallCount = Math.min(callCountVm2, callCountVm1); - int maxCallCount = Math.max(callCountVm1, callCountVm2); - assertEquals("Must not be called beyond exception threshold", - 10, maxCallCount); - assertEquals("Other action's exception cancels globally", - 9, minCallCount); - } - - @Test - public void verifyCustomActivateRegistersListener() { - backend.preActivate(); - verify(mockRegistrar).register(backend); - } - - @Test - public void verifyCustomDeactivateUnregistersListener() { - backend.postDeactivate(); - verify(mockRegistrar).unregister(backend); - } - - @Test - public void verifyRegisteredActionPerformed() { - String vmId = "test-vm-id"; - int pid = 123; - backend.vmStatusChanged(Status.VM_ACTIVE, vmId, pid); - VmPollingAction action = mock(VmPollingAction.class); - backend.registerAction(action); - backend.doScheduledActions(); - - verify(action).run(eq(vmId), eq(pid)); - } - - @Test - public void verifyMultipleRegisteredActionsPerformed() { - String vmId = "test-vm-id"; - int pid = 123; - backend.vmStatusChanged(Status.VM_ACTIVE, vmId, pid); - VmPollingAction action1 = mock(VmPollingAction.class); - VmPollingAction action2 = mock(VmPollingAction.class); - backend.registerAction(action1); - backend.registerAction(action2); - backend.doScheduledActions(); - - verify(action1).run(eq(vmId), eq(pid)); - verify(action2).run(eq(vmId), eq(pid)); - } - - @Test - public void verifyActionsPerformedOnMultipleVms() { - String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2"; - int pid1 = 123, pid2 = 456; - backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1); - backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2); - VmPollingAction action = mock(VmPollingAction.class); - backend.registerAction(action); - backend.doScheduledActions(); - - verify(action).run(eq(vmId1), eq(pid1)); - verify(action).run(eq(vmId2), eq(pid2)); - } - - @Test - public void verifyMultipleRegisteredActionsPerformedOnMultipleVms() { - String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2"; - int pid1 = 123, pid2 = 456; - backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1); - backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2); - VmPollingAction action1 = mock(VmPollingAction.class); - VmPollingAction action2 = mock(VmPollingAction.class); - backend.registerAction(action1); - backend.registerAction(action2); - backend.doScheduledActions(); - - verify(action1).run(eq(vmId1), eq(pid1)); - verify(action1).run(eq(vmId2), eq(pid2)); - verify(action2).run(eq(vmId1), eq(pid1)); - verify(action2).run(eq(vmId2), eq(pid2)); - } - - @Test - public void verifyUnregisteredActionNotPerformed() { - String vmId = "test-vm-id"; - int pid = 123; - backend.vmStatusChanged(Status.VM_ACTIVE, vmId, pid); - VmPollingAction action1 = mock(VmPollingAction.class); - VmPollingAction action2 = mock(VmPollingAction.class); - backend.registerAction(action1); - backend.registerAction(action2); - backend.doScheduledActions(); // Triggers both - backend.unregisterAction(action1); - backend.doScheduledActions(); // Triggers only action2 - - verify(action1, times(1)).run(eq(vmId), eq(pid)); - verify(action2, times(2)).run(eq(vmId), eq(pid)); - } - - @Test - public void verifyVmStatusChangedStartedAndActiveResultInPolling() { - String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2"; - int pid1 = 123, pid2 = 456; - backend.vmStatusChanged(Status.VM_STARTED, vmId1, pid1); - backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2); - VmPollingAction action = mock(VmPollingAction.class); - backend.registerAction(action); - backend.doScheduledActions(); - - verify(action).run(eq(vmId1), eq(pid1)); - verify(action).run(eq(vmId2), eq(pid2)); - } - - @Test - public void verifyVmStatusChangedStopsResultsInNoMorePolling() { - String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2"; - int pid1 = 123, pid2 = 456; - backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1); - backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2); - VmPollingAction action = mock(VmPollingAction.class); - backend.registerAction(action); - backend.doScheduledActions(); // Triggers for both vms - backend.vmStatusChanged(Status.VM_STOPPED, vmId1, pid1); - backend.doScheduledActions(); // Triggers only for vm2 - - verify(action, times(1)).run(eq(vmId1), eq(pid1)); - verify(action, times(2)).run(eq(vmId2), eq(pid2)); - } - - @Test - public void verifyGetSetObserveNewJvmWorksAsExpected() { - String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2"; - int pid1 = 123, pid2 = 456; - backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1); - backend.setObserveNewJvm(false); - backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2); // Should be ignored. - VmPollingAction action = mock(VmPollingAction.class); - backend.registerAction(action); - backend.doScheduledActions(); - - verify(action).run(eq(vmId1), eq(pid1)); - verify(action, never()).run(eq(vmId2), eq(pid2)); - } - - private static class BadVmPollingAction implements VmPollingAction { - - private final Map<String, Integer> callCounts = new HashMap<>(); - - @Override - public void run(String vmId, int pid) { - Integer currCount = callCounts.remove(vmId); - if (currCount == null) { - currCount = Integer.valueOf(1); - } else { - currCount++; - } - callCounts.put(vmId, Integer.valueOf(currCount)); - throw new RuntimeException("doScheduledActions() testing!"); - } - - private Integer getCallCount(String vmId) { - return callCounts.get(vmId); - } - - } -}
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/internal/TestLogHandler.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.internal; - -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.LogRecord; - -/* - * Test log handler used for VmMonitor log testing. - */ -public class TestLogHandler extends Handler { - - private static final String PROCESS_NOT_FOUND = "Process not found"; - private static final String EXPECTED_UNABLE_TO_ATTACH_PROC_NOT_FOUND_FMT = - "Tried to attach to a process which no longer exists. Pid was %d"; - private static final String EXPECTED_UNABLE_TO_ATTACH_MSG_FMT = - "unable to attach to vm %d"; - private boolean unableToAttachLoggedWarning; - private boolean unableToAttachLoggedFinest; - private final String unableToAttachMsg; - private final String procNotFoundMsg; - - TestLogHandler(int pid) { - unableToAttachMsg = String.format(EXPECTED_UNABLE_TO_ATTACH_MSG_FMT, pid); - procNotFoundMsg = String.format(EXPECTED_UNABLE_TO_ATTACH_PROC_NOT_FOUND_FMT, pid); - } - - @Override - public void publish(LogRecord record) { - String logMessage = record.getMessage(); - if (record.getLevel().intValue() >= Level.WARNING.intValue() && - logMessage.equals(unableToAttachMsg)) { - unableToAttachLoggedWarning = diagnoseRecord(record); - } - if (record.getLevel().intValue() == Level.FINEST.intValue() && - logMessage.equals(procNotFoundMsg)) { - unableToAttachLoggedFinest = diagnoseRecord(record); - } - } - - private boolean diagnoseRecord(LogRecord record) { - Throwable thrown = record.getThrown(); - if (thrown != null && thrown.getCause() instanceof IllegalArgumentException) { - return true; - } - return false; - } - - @Override - public void flush() { - // nothing - } - - @Override - public void close() throws SecurityException { - // nothing - } - - boolean isUnableToAttachLoggedAsWarning() { - return unableToAttachLoggedWarning; - } - - boolean isUnableToAttachLoggedAsWarningUnrelated() { - return !unableToAttachLoggedWarning && !unableToAttachLoggedFinest; - } - - boolean isUnableToAttachLoggedAsFinest() { - return unableToAttachLoggedFinest; - } - -} -
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/internal/VmListenerWrapperTest.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.internal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.redhat.thermostat.backend.VmUpdate; -import com.redhat.thermostat.backend.VmUpdateException; -import com.redhat.thermostat.backend.VmUpdateListener; -import com.redhat.thermostat.common.internal.test.Bug; - -import sun.jvmstat.monitor.Monitor; -import sun.jvmstat.monitor.MonitorException; -import sun.jvmstat.monitor.MonitoredVm; -import sun.jvmstat.monitor.event.VmEvent; - -public class VmListenerWrapperTest { - - private VmListenerWrapper wrapper; - private MonitoredVm monitoredVm; - private VmUpdateListener listener; - - @Before - public void setUp() throws Exception { - listener = mock(VmUpdateListener.class); - monitoredVm = mock(MonitoredVm.class); - wrapper = new VmListenerWrapper(listener, monitoredVm); - } - - /** - * Verify that a bad listener which throws exceptions gets removed - * from the JVM beyond a threshold. - * @throws MonitorException - */ - @Bug(id = "3242", - summary = "Adverse Backend breaks other Backends badly ", - url = "http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=3242") - @Test - public void testMonitorsUpdatedListenerExceptions() throws MonitorException { - final int beyondThresholdLimit = 11; - VmUpdateListener badListener = new VmUpdateListener() { - @Override - public void countersUpdated(VmUpdate update) { - throw new RuntimeException("countersUpdated() testing!"); - } - }; - VmListenerWrapper vmListenerWrapper = new VmListenerWrapper(badListener, monitoredVm); - VmEvent event = mock(VmEvent.class); - for (int i = 0; i < beyondThresholdLimit; i++) { - when(event.getMonitoredVm()).thenReturn(monitoredVm); - - vmListenerWrapper.monitorsUpdated(event); - - } - verify(monitoredVm, times(1)).removeVmListener(vmListenerWrapper); - } - - @Test - public void testMonitorsUpdated() { - VmEvent event = mock(VmEvent.class); - when(event.getMonitoredVm()).thenReturn(monitoredVm); - - wrapper.monitorsUpdated(event); - - ArgumentCaptor<VmUpdateImpl> captor = ArgumentCaptor.forClass(VmUpdateImpl.class); - verify(listener).countersUpdated(captor.capture()); - VmUpdateImpl update = captor.getValue(); - assertEquals(wrapper, update.getWrapper()); - } - - @Test(expected=AssertionError.class) - public void testMonitorsUpdatedWrongVm() { - VmEvent event = mock(VmEvent.class); - MonitoredVm badVm = mock(MonitoredVm.class); - when(event.getMonitoredVm()).thenReturn(badVm); - - wrapper.monitorsUpdated(event); - } - - @Test - public void testGetCounter() throws MonitorException, VmUpdateException { - final String counter = "myCounter"; - - Monitor monitor = mock(Monitor.class); - when(monitoredVm.findByName(counter)).thenReturn(monitor); - - Monitor result = wrapper.getMonitor(counter); - assertEquals(monitor, result); - } - - @Test - public void testGetCounterNotFound() throws MonitorException, VmUpdateException { - final String counter = "myCounter"; - - when(monitoredVm.findByName(counter)).thenReturn(null); - - Monitor result = wrapper.getMonitor(counter); - assertNull(result); - } - - @Test(expected=VmUpdateException.class) - public void testGetCounterError() throws MonitorException, VmUpdateException { - final String counter = "myCounter"; - - when(monitoredVm.findByName(counter)).thenThrow(new MonitorException()); - - wrapper.getMonitor(counter); - } - -} -
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/internal/VmMonitorTest.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,285 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.internal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.isA; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import java.net.URISyntaxException; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import com.redhat.thermostat.common.portability.ProcessChecker; -import com.redhat.thermostat.backend.VmUpdateListener; - -import sun.jvmstat.monitor.HostIdentifier; -import sun.jvmstat.monitor.MonitorException; -import sun.jvmstat.monitor.MonitoredHost; -import sun.jvmstat.monitor.MonitoredVm; -import sun.jvmstat.monitor.VmIdentifier; -import sun.jvmstat.monitor.event.VmListener; - -public class VmMonitorTest { - - private static final String PROCESS_NOT_FOUND = "Process not found"; - private static final int MONITOR_EXCEPTION_THROWING_PID = 999; - private VmMonitor monitor; - private HostIdentifier hostIdentifier; - private MonitoredHost host; - private MonitoredVm monitoredVm; - private ProcessChecker checker; - private TestLogHandler handler; - private Logger logger; - private Level savedLoggingLevel; - - @After - public void tearDown() { - if (handler != null) { - logger.removeHandler(handler); - handler = null; - } - logger.setLevel(savedLoggingLevel); - } - - @Before - public void setUp() throws Exception { - savedLoggingLevel = setupTestLoggerAndReturnOriginalLevel(); - - hostIdentifier = mock(HostIdentifier.class); - when(hostIdentifier.resolve(isA(VmIdentifier.class))).then(new Answer<VmIdentifier>() { - @Override - public VmIdentifier answer(InvocationOnMock invocation) throws Throwable { - return (VmIdentifier) invocation.getArguments()[0]; - } - }); - host = mock(MonitoredHost.class); - when(host.getHostIdentifier()).thenReturn(hostIdentifier); - - checker = mock(ProcessChecker.class); - when(checker.exists(isA(Integer.class))).thenReturn(false); - - monitoredVm = mock(MonitoredVm.class); - - monitor = new VmMonitor(checker); - monitor.setHost(host); - } - - private Level setupTestLoggerAndReturnOriginalLevel() { - logger = Logger.getLogger("com.redhat.thermostat"); - Level originalLevel = logger.getLevel(); - logger.setLevel(Level.FINEST); - handler = new TestLogHandler(MONITOR_EXCEPTION_THROWING_PID); - logger.addHandler(handler); - return originalLevel; - } - - @Test - public void testNewVM() throws MonitorException, URISyntaxException { - final int VM_PID = 1; - VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID)); - when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm); - - VmUpdateListener listener = mock(VmUpdateListener.class); - monitor.handleNewVm(listener, VM_PID); - - // Check listener registered - ArgumentCaptor<VmListenerWrapper> captor = ArgumentCaptor.forClass(VmListenerWrapper.class); - verify(monitoredVm).addVmListener(captor.capture()); - VmListenerWrapper wrapper = captor.getValue(); - assertEquals(listener, wrapper.getVmUpdateListener()); - - // Check pid map - assertTrue(monitor.getPidToDataMap().containsKey(VM_PID)); - assertEquals(wrapper, monitor.getPidToDataMap().get(VM_PID).getSecond()); - } - - /* - * English locale "Process not found". It must not matter really for this - * test. See the next test which verifies this. - */ - @Test - public void testNewVMWithProcessNotFoundDoesNotLogWarning() throws Exception { - String exceptionMsg = PROCESS_NOT_FOUND; - basicProcNotFoundTest(exceptionMsg); - } - - /* - * Random exception message as the exact message will be locale dependent. - */ - @Test - public void testNewVMWithProcessNotFoundDoesNotLogWarning2() throws Exception { - String exceptionMsg = "foo but not bar"; - basicProcNotFoundTest(exceptionMsg); - } - - private void basicProcNotFoundTest(String exceptionMsg) throws Exception { - IllegalArgumentException iae = new IllegalArgumentException(exceptionMsg); - MonitorException procNotFound = new MonitorException(iae); - assertEquals(iae, procNotFound.getCause()); - - VmIdentifier vmID = new VmIdentifier(String.valueOf(MONITOR_EXCEPTION_THROWING_PID)); - when(host.getMonitoredVm(vmID)).thenThrow(procNotFound); - VmUpdateListener listener = mock(VmUpdateListener.class); - - monitor.handleNewVm(listener, MONITOR_EXCEPTION_THROWING_PID); - assertFalse(handler.isUnableToAttachLoggedAsWarning()); - assertTrue(handler.isUnableToAttachLoggedAsFinest()); - assertFalse(handler.isUnableToAttachLoggedAsWarningUnrelated()); - } - - @Test - public void testNewVMUnrelatedCausedMonitorExceptionLogWarning() throws Exception { - MonitorException procNotFound = new MonitorException("unknown"); - - VmIdentifier vmID = new VmIdentifier(String.valueOf(MONITOR_EXCEPTION_THROWING_PID)); - when(host.getMonitoredVm(vmID)).thenThrow(procNotFound); - VmUpdateListener listener = mock(VmUpdateListener.class); - - monitor.handleNewVm(listener, MONITOR_EXCEPTION_THROWING_PID); - assertFalse(handler.isUnableToAttachLoggedAsWarning()); - assertFalse(handler.isUnableToAttachLoggedAsFinest()); - assertTrue(handler.isUnableToAttachLoggedAsWarningUnrelated()); - } - - @Test - public void testStatVMGetMonitoredVmFails() throws MonitorException { - final int VM_PID = 1; - MonitorException monitorException = new MonitorException(); - when(host.getMonitoredVm(isA(VmIdentifier.class))).thenThrow(monitorException); - - VmUpdateListener listener = mock(VmUpdateListener.class); - monitor.handleNewVm(listener, VM_PID); - - assertFalse(monitor.getPidToDataMap().containsKey(VM_PID)); - } - - @Test - public void testStoppedVM() throws MonitorException, URISyntaxException { - final int VM_PID = 1; - VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID)); - when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm); - - VmUpdateListener listener = mock(VmUpdateListener.class); - - monitor.handleNewVm(listener, VM_PID); - monitor.handleStoppedVm(VM_PID); - - // Check listener unregistered - ArgumentCaptor<VmListenerWrapper> captor = ArgumentCaptor.forClass(VmListenerWrapper.class); - verify(monitoredVm).removeVmListener(captor.capture()); - VmListenerWrapper wrapper = captor.getValue(); - assertEquals(listener, wrapper.getVmUpdateListener()); - - assertFalse(monitor.getPidToDataMap().containsKey(VM_PID)); - } - - @Test - public void testUnknownVMStopped() throws URISyntaxException, MonitorException { - final int VM_PID = 1; - VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID)); - when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm); - - monitor.handleStoppedVm(VM_PID); - - verifyNoMoreInteractions(monitoredVm); - } - - @Test - public void testErrorRemovingVmListener() throws URISyntaxException, MonitorException { - final int VM_PID = 1; - VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID)); - when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm); - - MonitorException monitorException = new MonitorException(); - doThrow(monitorException).when(monitoredVm).removeVmListener(any(VmListener.class)); - - VmUpdateListener listener = mock(VmUpdateListener.class); - monitor.handleNewVm(listener, VM_PID); - monitor.handleStoppedVm(VM_PID); - - verify(monitoredVm).detach(); - } - - @Test - public void testRemoveAllListeners() throws URISyntaxException, MonitorException { - final int VM_PID1 = 1; - final int VM_PID2 = 2; - - VmIdentifier VM_ID1 = new VmIdentifier(String.valueOf(VM_PID1)); - when(host.getMonitoredVm(VM_ID1)).thenReturn(monitoredVm); - - MonitoredVm monitoredVm2 = mock(MonitoredVm.class); - VmIdentifier VM_ID2 = new VmIdentifier(String.valueOf(VM_PID2)); - when(host.getMonitoredVm(VM_ID2)).thenReturn(monitoredVm2); - - VmUpdateListener listener1 = mock(VmUpdateListener.class); - VmUpdateListener listener2 = mock(VmUpdateListener.class); - monitor.handleNewVm(listener1, VM_PID1); - monitor.handleNewVm(listener2, VM_PID2); - - monitor.removeVmListeners(); - - ArgumentCaptor<VmListenerWrapper> captor1 = ArgumentCaptor.forClass(VmListenerWrapper.class); - verify(monitoredVm).removeVmListener(captor1.capture()); - VmListenerWrapper wrapper1 = captor1.getValue(); - assertEquals(listener1, wrapper1.getVmUpdateListener()); - - ArgumentCaptor<VmListenerWrapper> captor2 = ArgumentCaptor.forClass(VmListenerWrapper.class); - verify(monitoredVm2).removeVmListener(captor2.capture()); - VmListenerWrapper wrapper2 = captor2.getValue(); - assertEquals(listener2, wrapper2.getVmUpdateListener()); - - assertEquals(0, monitor.getPidToDataMap().size()); - } - -} -
--- a/agent/core/src/test/java/com/redhat/thermostat/backend/internal/VmUpdateImplTest.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.internal; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - -import org.junit.Before; -import org.junit.Test; - -import sun.jvmstat.monitor.Monitor; - -import com.redhat.thermostat.backend.VmUpdateException; - -public class VmUpdateImplTest { - - private VmUpdateImpl update; - private VmListenerWrapper wrapper; - - @Before - public void setUp() throws Exception { - wrapper = mock(VmListenerWrapper.class); - update = new VmUpdateImpl(wrapper); - } - - @Test - public void testGetPerformanceCounterLong() throws VmUpdateException { - final String counter = "myCounter"; - final Long value = 9001L; - Monitor monitor = mock(Monitor.class); - when(monitor.getValue()).thenReturn(value); - when(wrapper.getMonitor(counter)).thenReturn(monitor); - - Long result = update.getPerformanceCounterLong(counter); - assertEquals(value, result); - } - - @Test(expected=ClassCastException.class) - public void testGetPerformanceCounterLongBadType() throws VmUpdateException { - final String counter = "myCounter"; - final String value = "myValue"; - Monitor monitor = mock(Monitor.class); - when(monitor.getValue()).thenReturn(value); - when(wrapper.getMonitor(counter)).thenReturn(monitor); - - update.getPerformanceCounterLong(counter); - } - - @Test - public void testGetPerformanceCounterLongNoCounter() throws VmUpdateException { - final String counter = "myCounter"; - when(wrapper.getMonitor(counter)).thenReturn(null); - - Long result = update.getPerformanceCounterLong(counter); - assertNull(result); - } - - @Test - public void testGetPerformanceCounterString() throws VmUpdateException { - final String counter = "myCounter"; - final String value = "myValue"; - Monitor monitor = mock(Monitor.class); - when(monitor.getValue()).thenReturn(value); - when(wrapper.getMonitor(counter)).thenReturn(monitor); - - String result = update.getPerformanceCounterString(counter); - assertEquals(value, result); - } - - @Test(expected=ClassCastException.class) - public void testGetPerformanceCounterStringBadType() throws VmUpdateException { - final String counter = "myCounter"; - final Long value = 9001L; - Monitor monitor = mock(Monitor.class); - when(monitor.getValue()).thenReturn(value); - when(wrapper.getMonitor(counter)).thenReturn(monitor); - - update.getPerformanceCounterString(counter); - } - - @Test - public void testGetPerformanceCounterStringNoCounter() throws VmUpdateException { - final String counter = "myCounter"; - when(wrapper.getMonitor(counter)).thenReturn(null); - - String result = update.getPerformanceCounterString(counter); - assertNull(result); - } - -} -
--- a/distribution/assembly/plugin-assembly.xml Thu Jun 08 20:16:03 2017 +0200 +++ b/distribution/assembly/plugin-assembly.xml Fri Jun 09 16:38:44 2017 +0200 @@ -50,6 +50,9 @@ <unpack>true</unpack> <includes> <include>com.redhat.thermostat:thermostat-host-overview-distribution</include> + <include>com.redhat.thermostat:thermostat-jvm-overview-distribution</include> + <include>com.redhat.thermostat:thermostat-vm-gc-distribution</include> + <include>com.redhat.thermostat:thermostat-vm-memory-distribution</include> <!-- <include>com.redhat.thermostat:thermostat-host-cpu-distribution</include>--> <!-- <include>com.redhat.thermostat:thermostat-host-memory-distribution</include>--> <!-- <include>com.redhat.thermostat:thermostat-numa-distribution</include>--> @@ -58,11 +61,9 @@ <!-- <include>com.redhat.thermostat:thermostat-vm-classstat-distribution</include>--> <!-- <include>com.redhat.thermostat:thermostat-vm-compiler-distribution</include>--> <!-- <include>com.redhat.thermostat:thermostat-vm-cpu-distribution</include>--> - <include>com.redhat.thermostat:thermostat-vm-gc-distribution</include> <!-- <include>com.redhat.thermostat:thermostat-vm-heap-analysis-distribution</include>--> <!-- <include>com.redhat.thermostat:thermostat-vm-io-distribution</include>--> <!-- <include>com.redhat.thermostat:thermostat-vm-jmx-distribution</include>--> - <include>com.redhat.thermostat:thermostat-vm-memory-distribution</include> <!-- <include>com.redhat.thermostat:thermostat-vm-profiler-distribution</include>--> <!-- <include>com.redhat.thermostat:thermostat-killvm-distribution</include>--> <!-- <include>com.redhat.thermostat:thermostat-vm-numa-distribution</include>-->
--- a/distribution/pom.xml Thu Jun 08 20:16:03 2017 +0200 +++ b/distribution/pom.xml Fri Jun 09 16:38:44 2017 +0200 @@ -131,11 +131,6 @@ <dependencies> <dependency> <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-keyring</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> <artifactId>thermostat-agent-ipc-unixsocket-server</artifactId> <version>${project.version}</version> </dependency> @@ -497,6 +492,30 @@ <version>${project.version}</version> <type>zip</type> </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-jvm-overview-distribution</artifactId> + <version>${project.version}</version> + <type>zip</type> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-vm-gc-distribution</artifactId> + <version>${project.version}</version> + <type>zip</type> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-vm-memory-distribution</artifactId> + <version>${project.version}</version> + <type>zip</type> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-killvm-distribution</artifactId> + <version>${project.version}</version> + <type>zip</type> + </dependency> <!--<dependency>--> <!--<groupId>com.redhat.thermostat</groupId>--> <!--<artifactId>thermostat-host-cpu-distribution</artifactId>--> @@ -560,12 +579,6 @@ <!--<version>${project.version}</version>--> <!--<type>zip</type>--> <!--</dependency>--> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-vm-gc-distribution</artifactId> - <version>${project.version}</version> - <type>zip</type> - </dependency> <!--<dependency>--> <!--<groupId>com.redhat.thermostat</groupId>--> <!--<artifactId>thermostat-vm-heap-analysis-distribution</artifactId>--> @@ -584,24 +597,12 @@ <!--<version>${project.version}</version>--> <!--<type>zip</type>--> <!--</dependency>--> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-vm-memory-distribution</artifactId> - <version>${project.version}</version> - <type>zip</type> - </dependency> <!--<dependency>--> <!--<groupId>com.redhat.thermostat</groupId>--> <!--<artifactId>thermostat-vm-profiler-distribution</artifactId>--> <!--<version>${project.version}</version>--> <!--<type>zip</type>--> <!--</dependency>--> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-killvm-distribution</artifactId> - <version>${project.version}</version> - <type>zip</type> - </dependency> </dependencies> </project>
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java Thu Jun 08 20:16:03 2017 +0200 +++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -46,7 +46,6 @@ import com.redhat.thermostat.launcher.Launcher; import com.redhat.thermostat.shared.config.CommonPaths; import com.redhat.thermostat.storage.dao.AgentInfoDAO; -import com.redhat.thermostat.storage.dao.VmInfoDAO; import com.redhat.thermostat.testutils.StubBundleContext; import org.junit.Before; import org.junit.Test; @@ -174,7 +173,6 @@ MultipleServiceTracker unusedTracker = mock(MultipleServiceTracker.class); Class<?>[] vmIdCompleterDeps = new Class[] { - VmInfoDAO.class, AgentInfoDAO.class }; whenNew(MultipleServiceTracker.class).withParameterTypes(BundleContext.class, Class[].class, Action.class).withArguments(eq(context),
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/pom.xml Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,181 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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 + <http://www.gnu.org/licenses/>. + + 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. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <artifactId>thermostat-jvm-overview</artifactId> + <groupId>com.redhat.thermostat</groupId> + <version>1.99.12-SNAPSHOT</version> + </parent> + + <artifactId>thermostat-jvm-overview-agent</artifactId> + <packaging>bundle</packaging> + <name>Thermostat JVM Overview Agent plugin</name> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor> + <Bundle-SymbolicName>com.redhat.thermostat.jvm.overview</Bundle-SymbolicName> + <Export-Package> + com.redhat.thermostat.jvm.overview.agent, + com.redhat.thermostat.jvm.overview.agent.model, + </Export-Package> + <Private-Package> + com.redhat.thermostat.jvm.overview.agent.internal, + com.redhat.thermostat.jvm.overview.agent.internal.model, + </Private-Package> + <!-- Do not autogenerate uses clauses in Manifests --> + <_nouses>true</_nouses> + </instructions> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-scr-plugin</artifactId> + <executions> + <execution> + <id>generate-scr-scrdescriptor</id> + <goals> + <goal>scr</goal> + </goals> + </execution> + </executions> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-resources-plugin</artifactId> + <executions> + <execution> + <id>copy</id> + <phase>generate-resources</phase> + <goals> + <goal>copy-resources</goal> + </goals> + <configuration> + <overwrite>true</overwrite> + <outputDirectory>${project.build.directory}</outputDirectory> + <resources> + <resource> + <directory>../../../common/portability/target</directory> + <includes> + <include>${sharedlib.prefix}thermostat-common-portability${sharedlib.suffix}</include> + </includes> + </resource> + </resources> + </configuration> + </execution> + </executions> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <!-- the test needs to link to common-portability native libraries --> + <systemPropertyVariables> + <com.redhat.thermostat.shared.loader.testNativesHome>${project.build.directory}</com.redhat.thermostat.shared.loader.testNativesHome> + </systemPropertyVariables> + </configuration> + </plugin> + + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.core</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.compendium</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-common-core</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-common-portability</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-agent-core</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-storage-core</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-common-test</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <!-- declarative services --> + <dependency> + <groupId>org.apache.felix</groupId> + <artifactId>org.apache.felix.scr.annotations</artifactId> + </dependency> + </dependencies> +</project>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmBlacklist.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,72 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent; + +import com.redhat.thermostat.common.Filter; + +/** + * Maintains a list of JVM processes that Thermostat should not + * monitor. + */ +public interface VmBlacklist { + + /** + * Adds a {@link Filter} to the blacklist. Virtual machines whose + * main class match the filter will not be monitored. + * @param filter - a filter whose matching VMs should not be monitored + */ + void addVmFilter(Filter<String> filter); + + /** + * Removes a {@link Filter} from the blacklist. New virtual machines + * will no longer be tested against this filter for blacklisting. + * @param filter - a filter previously in the blacklist + */ + void removeVmFilter(Filter<String> filter); + + /** + * Returns whether the given virtual machine should be monitored + * by matching it against filters in the blacklist. If any filter + * matches, then this method will return true. + * @param mainClass - a class name to check against classes covered + * by this blacklist + * @return true if blacklisted, false otherwise + */ + boolean isBlacklisted(String mainClass); + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmListenerBackend.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,190 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.backend.BaseBackend; +import com.redhat.thermostat.backend.BackendException; +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.storage.core.WriterID; + +/** + * This class is a convenient subclass of {@link com.redhat.thermostat.backend.Backend} (via {@link BaseBackend}) for those + * that need to attach {@link VmUpdateListener} in response to starting and stopping of JVMs on a + * host. + * + * @see package com.redhat.thermostat.jvm.overview.agent.VmStatusListener + * @see com.redhat.thermostat.backend.Backend + * @see BaseBackend + */ +public abstract class VmListenerBackend extends BaseBackend implements VmStatusListener { + + private static final Logger logger = LoggingUtils.getLogger(VmListenerBackend.class); + + private WriterID writerId; + private VmStatusListenerRegistrar registrar; + private VmMonitor monitor; + private boolean started; + private boolean initialized; + + public VmListenerBackend(String backendName, String description, String vendor, boolean observeNewJvm) { + this(backendName, description, vendor, "1.0", observeNewJvm); + } + + public VmListenerBackend(String backendName, String description, String vendor) { + this(backendName, description, vendor, "1.0", false); + } + + public VmListenerBackend(String backendName, String description, + String vendor, String version, boolean observeNewJvm) { + super(backendName, description, vendor, version, observeNewJvm); + try { + this.monitor = new VmMonitor(); + } catch (BackendException e) { + logger.log(Level.SEVERE, "Unable to create backend", e); + } + } + + /** + * {@inheritDoc} + * + * <p> + * Registers a VmUpdateListener to begin receiving VM lifecycle events. + * Subclasses should call <code>super.activate()</code> when overriding this method. + * </p> + * <p> + * This {@link VmListenerBackend} should be initialized via + * {@link #initialize(WriterID, VmStatusListenerRegistrar)} before calling this method. + * </p> + */ + @Override + public boolean activate() { + if (!initialized) { + logger.warning("Backend not started, initialize must be called before activate"); + } else if (!started && monitor != null) { + registrar.register(this); + started = true; + } + return started; + } + + /** + * {@inheritDoc} + * + * <p> + * Unregisters the VmUpdateListener to stop receiving VM lifecycle events. + * Subclasses should call <code>super.deactivate()</code> when overriding this method. + * </p> + */ + @Override + public boolean deactivate() { + if (started && monitor != null) { + registrar.unregister(this); + monitor.removeVmListeners(); + started = false; + } + return !started; + } + + @Override + public boolean isActive() { + return started; + } + + public void vmStatusChanged(Status newStatus, String vmId, int pid) { + switch (newStatus) { + case VM_STARTED: + /* fall-through */ + case VM_ACTIVE: + if (getObserveNewJvm()) { + String wId = writerId.getWriterID(); + VmUpdateListener listener = null; + try { + listener = createVmListener(wId, vmId, pid); + } catch (Throwable t) { + logger.log(Level.INFO, "Creating the VM listener for a VmListenerBackend threw an exception. Going to ignore the backend!", t); + } + if (listener != null) { + monitor.handleNewVm(listener, pid); + } + } else { + logger.log(Level.FINE, "skipping new vm " + pid); + } + break; + case VM_STOPPED: + monitor.handleStoppedVm(pid); + break; + default: + break; + } + } + + /** + * Initializes this {@link VmListenerBackend} with necessary services. This method + * must be called before {@link #activate()}. + * @param writerId service uniquely identifying this agent + * @param registrar responsible for registering and unregistering instances of {@link VmStatusListener} + * @param version version number of this backend + */ + protected void initialize(WriterID writerId, VmStatusListenerRegistrar registrar, String version) { + this.writerId = writerId; + this.registrar = registrar; + setVersion(version); + this.initialized = true; + } + + /** + * Creates a new {@link VmUpdateListener} for the virtual machine + * specified by the pid. This method is called when a new + * JVM is started or for JVMs already active when this Backend + * was activated. + * @param vmId unique identifier of the JVM + * @param pid the process ID of the JVM + * @return a new listener for the VM specified by pid + */ + protected abstract VmUpdateListener createVmListener(String writerId, String vmId, int pid); + + /* + * For testing purposes only. + */ + void setMonitor(VmMonitor monitor) { + this.monitor = monitor; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmMonitor.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,150 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent; + +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.backend.BackendException; +import com.redhat.thermostat.jvm.overview.agent.internal.VmListenerWrapper; +import sun.jvmstat.monitor.HostIdentifier; +import sun.jvmstat.monitor.MonitorException; +import sun.jvmstat.monitor.MonitoredHost; +import sun.jvmstat.monitor.MonitoredVm; +import sun.jvmstat.monitor.VmIdentifier; + +import com.redhat.thermostat.common.portability.ProcessChecker; +import com.redhat.thermostat.common.Pair; +import com.redhat.thermostat.common.utils.LoggingUtils; + +public class VmMonitor { + + private final Logger logger = LoggingUtils.getLogger(VmMonitor.class); + + private final ProcessChecker processChecker; + private MonitoredHost host; + private Map<Integer, Pair<MonitoredVm, VmListenerWrapper>> pidToData = new HashMap<>(); + + public VmMonitor() throws BackendException { + this(new ProcessChecker()); + } + + public VmMonitor(ProcessChecker processChecker) throws BackendException { + this.processChecker = processChecker; + try { + HostIdentifier hostId = new HostIdentifier((String) null); + host = MonitoredHost.getMonitoredHost(hostId); + } catch (MonitorException me) { + throw new BackendException("Problems with connecting jvmstat to local machine", me); + } catch (URISyntaxException use) { + throw new BackendException("Failed to create host identifier", use); + } + } + + public void handleNewVm(VmUpdateListener listener, int pid) { + try { + MonitoredVm vm = host.getMonitoredVm(host.getHostIdentifier().resolve(new VmIdentifier(String.valueOf(pid)))); + VmListenerWrapper wrapper = new VmListenerWrapper(listener, vm); + vm.addVmListener(wrapper); + + pidToData.put(pid, new Pair<>(vm, wrapper)); + logger.finer("Attached " + listener.getClass().getName() + " for VM: " + pid); + } catch (MonitorException e) { + logMsg(pid, e); + } catch (URISyntaxException e) { + logger.log(Level.WARNING, "unable to attach to vm " + pid, e); + } + } + + private void logMsg(int pid, MonitorException e) { + Throwable cause = e.getCause(); + if (cause != null && cause instanceof IllegalArgumentException && !processChecker.exists(pid)) { + logger.log(Level.FINEST, "Tried to attach to a process which no longer exists. Pid was " + pid, e); + } else { + logger.log(Level.WARNING, "unable to attach to vm" + pid, e); + } + } + + public void handleStoppedVm(int pid) { + Pair<MonitoredVm, VmListenerWrapper> data = pidToData.remove(pid); + // we were not monitoring pid at all, so nothing to do + if (data == null) { + return; + } + + MonitoredVm vm = data.getFirst(); + VmListenerWrapper listener = data.getSecond(); + try { + vm.removeVmListener(listener); + } catch (MonitorException e) { + logger.log(Level.WARNING, "can't remove vm listener", e); + } + vm.detach(); + } + + public void removeVmListeners() { + for (Pair<MonitoredVm, VmListenerWrapper> data : pidToData.values()) { + MonitoredVm vm = data.getFirst(); + VmListenerWrapper listener = data.getSecond(); + try { + vm.removeVmListener(listener); + } catch (MonitorException e) { + logger.log(Level.WARNING, "can't remove vm listener", e); + } + } + pidToData.clear(); + } + + /* + * For testing purposes only. + */ + void setHost(MonitoredHost host) { + this.host = host; + } + + /* + * For testing purposes only. + */ + Map<Integer, Pair<MonitoredVm, VmListenerWrapper>> getPidToDataMap() { + return pidToData; + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmPollingAction.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,53 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent; + +/** + * An action to be performed at a regular interval as part of a + * {@link VmPollingBackend} implementation. + */ +public interface VmPollingAction { + + /** + * Run the action. + * + * @param vmId a String representation of the VmID on which to take action. + * @param pid the process ID of the JVM instance on which to take action. + */ + public void run(String vmId, int pid); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmPollingBackend.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,158 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.ScheduledExecutorService; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.backend.PollingBackend; +import com.redhat.thermostat.common.Pair; +import com.redhat.thermostat.common.Version; +import com.redhat.thermostat.common.utils.LoggingUtils; + +/** + * Convenience {@link com.redhat.thermostat.backend.Backend} class for implementations that will take some + * action for each monitored JVM process on a regular interval. Simply + * extend this class, implement any missing methods, and register one or + * more {@link VmPollingAction} implementations during instantiation. + */ +public abstract class VmPollingBackend extends PollingBackend implements VmStatusListener { + + private final Set<VmPollingAction> actions; + private final Map<String, Pair<Integer, VmPollingAction>> badActions; + private final Map<Integer, String> pidsToMonitor = new ConcurrentHashMap<>(); + private final VmStatusListenerRegistrar registrar; + private static final Logger logger = LoggingUtils.getLogger(VmPollingBackend.class); + private static final int EXCEPTIONS_THRESHOLD = 10; + + public VmPollingBackend(String name, String description, + String vendor, Version version, ScheduledExecutorService executor, + VmStatusListenerRegistrar registrar) { + super(name, description, vendor, version, executor); + this.registrar = registrar; + this.actions = new CopyOnWriteArraySet<>(); + this.badActions = new HashMap<>(); + } + + @Override + final public void preActivate() { + registrar.register(this); + } + + @Override + final public void postDeactivate() { + registrar.unregister(this); + } + + @Override + final public void doScheduledActions() { + for (Entry<Integer, String> entry : pidsToMonitor.entrySet()) { + int pid = entry.getKey(); + String vmId = entry.getValue(); + for (VmPollingAction action : actions) { + try { + action.run(vmId, pid); + } catch (Throwable t) { + handleActionException(action, vmId); + } + } + } + } + + private synchronized void handleActionException(VmPollingAction action, String vmId) { + final String actionName = action.getClass().getName(); + final String actionKey = actionName + vmId; + Pair<Integer, VmPollingAction> actionPair = badActions.remove(actionKey); + if (actionPair == null) { + actionPair = new Pair<>(Integer.valueOf(1), action); + } + int exceptionsPerAction = actionPair.getFirst(); + if (exceptionsPerAction < EXCEPTIONS_THRESHOLD) { + exceptionsPerAction++; + logger.info(VmPollingAction.class.getSimpleName() + " " + + actionName + " threw an exception"); + badActions.put(actionKey, new Pair<>(exceptionsPerAction, action)); + } else { + logger.fine("Removing " + actionName + " due to too many repeated exceptions."); + unregisterAction(action); + } + } + + /** + * Register an action to be performed at each polling interval. It is + * recommended that implementations register all such actions during + * instantiation. + */ + protected final void registerAction(VmPollingAction action) { + actions.add(action); + } + + /** + * Unregister an action so that it will no longer be performed at each + * polling interval. If no such action has been registered, this + * method has no effect. Depending on thread timing issues, the action + * may be performed once even after this method has been called. + */ + protected final void unregisterAction(VmPollingAction action) { + actions.remove(action); + } + + @Override + public void vmStatusChanged(Status newStatus, String vmId, int pid) { + switch (newStatus) { + case VM_STARTED: + /* fall-through */ + case VM_ACTIVE: + if (getObserveNewJvm()) { + pidsToMonitor.put(pid, vmId); + } else { + logger.log(Level.FINE, "skipping new vm " + pid); + } + break; + case VM_STOPPED: + pidsToMonitor.remove(pid); + break; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmStatusListener.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,72 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent; + +import com.redhat.thermostat.annotations.ExtensionPoint; + +/** + * A listener that is notified when a JVM starts or is stopped. + * <p> + * Register an instance of this class as an OSGi service, and it will be + * notified of all VM {@link Status} events. + */ +@ExtensionPoint +public interface VmStatusListener { + + enum Status { + + /** A VM has just started now */ + VM_STARTED, + + /** + * A delayed version of {@link #VM_STARTED}. A VM was started at some + * point in the past. The listener was not informed about it then + * (probably because the listener was not registered at the time), but + * is being informed about it now. + */ + VM_ACTIVE, + + /** A VM was stopped just now */ + VM_STOPPED, + } + + // TODO what other information other than vmId and pid may be useful for plugins? + + void vmStatusChanged(Status newStatus, String vmId, int pid); + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmStatusListenerRegistrar.java Fri Jun 09 16:38:44 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent; + +import java.util.HashMap; +import java.util.Map; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; + +/** + * Registers a {@link VmStatusListener} as an OSGi Service. + * <p> + * This is just a convenience wrapper over + * {@link BundleContext#registerService(String, Object, java.util.Dictionary)}. + * It does absolutely nothing special. + * + * @see VmStatusListener + */ +public class VmStatusListenerRegistrar { + + private final BundleContext context; + private final Map<VmStatusListener, ServiceRegistration> registrations = new HashMap<>(); + + public VmStatusListenerRegistrar(BundleContext context) { + this.context = context; + } + + public void register(VmStatusListener listener) { + registrations.put(listener, context.registerService(VmStatusListener.class.getName(), listener, null)); + } + + public void unregister(VmStatusListener listener) { + ServiceRegistration registration = registrations.remove(listener); + if (registration == null) { + throw new IllegalArgumentException("no listener found"); + } + + registration.unregister(); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmUpdate.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,69 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent; + +/** + * This interface can be used to query the performance counters + * of a monitored JVM when they are updated. + * @see package com.redhat.thermostat.jvm.overview.agent.VmUpdateListener#countersUpdated(VmUpdate) + */ +public interface VmUpdate { + + /** + * Queries the specified JVM performance counter with a Long data type. + * @param name - The name of the performance counter + * @return The current value of the requested counter, or null if no + * such counter exists + * @throws com.redhat.thermostat.jvm.overview.agent.VmUpdateException if there is + * a problem communicating with the JVM + * @throws ClassCastException if the value of the counter is not a Long + */ + Long getPerformanceCounterLong(String name) throws VmUpdateException; + + /** + * Queries the specified JVM performance counter with a String data type. + * @param name - The name of the performance counter + * @return The current value of the requested counter, or null if no + * such counter exists + * @throws VmUpdateException if there is a problem communicating with + * the JVM + * @throws ClassCastException if the value of the counter is not a String + */ + String getPerformanceCounterString(String name) throws VmUpdateException; + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmUpdateException.java Fri Jun 09 16:38:44 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent; + +/** + * Exception class indicating that a problem occurred accessing + * a monitored JVM's performance counters. + */ +public class VmUpdateException extends Exception { + + private static final long serialVersionUID = 7644805109896007513L; + + /** + * Constructs a VmUpdateException with no message. + */ + public VmUpdateException() { + super(); + } + + /** + * Constructs a VmUpdateException with an error message. + */ + public VmUpdateException(String msg) { + super(msg); + } + + /** + * Constructs a VmUpdateException with a cause. + */ + public VmUpdateException(Throwable cause) { + super(cause); + } + + /** + * Constructs a VmUpdateException with an error message and cause. + */ + public VmUpdateException(String msg, Throwable cause) { + super(msg, cause); + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/VmUpdateListener.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,54 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent; + +/** + * A listener that can be registered to receive updates for a + * JVM's performance counters. + * @see com.redhat.thermostat.jvm.overview.agent.VmListenerBackend#createVmListener(String, String, int) + */ +public interface VmUpdateListener { + + /** + * This method is called when the performance counters + * are updated for the JVM this listener is attached to. + * @param update - object to query performance counter values + */ + void countersUpdated(VmUpdate update); + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/JvmStatDataExtractor.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,106 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal; + +import sun.jvmstat.monitor.MonitorException; +import sun.jvmstat.monitor.MonitoredVm; +import sun.jvmstat.monitor.MonitoredVmUtil; + +/** + * A helper class to provide type-safe access to commonly used jvmstat monitors + * <p> + * Implementation details: For local vms, jvmstat uses a ByteBuffer + * corresponding to mmap()ed hsperfdata file. The hsperfdata file is updated + * asynchronously by the vm that created the file. The polling that jvmstat api + * provides is merely an abstraction over this (possibly always up-to-date) + * ByteBuffer. So the data this class extracts is as current as possible, and + * does not correspond to when the jvmstat update events fired. + */ +public class JvmStatDataExtractor { + + /* + * Note, there may be a performance issue to consider here. We have a lot of + * string constants. When we start adding some of the more heavyweight + * features, and running into CPU issues this may need to be reconsidered in + * order to avoid the String pool overhead. See also: + * http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#intern() + */ + + private final MonitoredVm vm; + + public JvmStatDataExtractor(MonitoredVm vm) { + this.vm = vm; + } + + public String getCommandLine() throws MonitorException { + return MonitoredVmUtil.commandLine(vm); + } + + public String getMainClass() throws MonitorException { + return MonitoredVmUtil.mainClass(vm, true); + } + + public String getJavaVersion() throws MonitorException { + return (String) vm.findByName("java.property.java.version").getValue(); + } + + public String getJavaHome() throws MonitorException { + return (String) vm.findByName("java.property.java.home").getValue(); + } + + public String getVmName() throws MonitorException { + return (String) vm.findByName("java.property.java.vm.name").getValue(); + } + + public String getVmInfo() throws MonitorException { + return (String) vm.findByName("java.property.java.vm.info").getValue(); + } + + public String getVmVersion() throws MonitorException { + return (String) vm.findByName("java.property.java.vm.version").getValue(); + } + + public String getVmArguments() throws MonitorException { + return MonitoredVmUtil.jvmArgs(vm); + } + + public long getVmStartTime() throws MonitorException { + return (long) vm.findByName("sun.rt.vmInitDoneTime").getValue(); + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/JvmStatHostListener.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,188 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal; + +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.common.Pair; +import com.redhat.thermostat.common.portability.ProcessUserInfo; +import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder; +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.jvm.overview.agent.VmBlacklist; +import com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status; +import com.redhat.thermostat.jvm.overview.agent.internal.model.InfoBuilderFactory; +import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoDAO; +import com.redhat.thermostat.jvm.overview.agent.model.VmInfo; +import com.redhat.thermostat.storage.core.WriterID; + +import sun.jvmstat.monitor.MonitorException; +import sun.jvmstat.monitor.MonitoredHost; +import sun.jvmstat.monitor.MonitoredVm; +import sun.jvmstat.monitor.VmIdentifier; +import sun.jvmstat.monitor.event.HostEvent; +import sun.jvmstat.monitor.event.HostListener; +import sun.jvmstat.monitor.event.VmStatusChangeEvent; + +class JvmStatHostListener implements HostListener { + + private static final Logger logger = LoggingUtils.getLogger(JvmStatHostListener.class); + + private final VmInfoDAO vmInfoDAO; + private final VmStatusChangeNotifier notifier; + private final ProcessUserInfoBuilder userInfoBuilder; + private final WriterID writerId; + private Map<Integer, Pair<String, MonitoredVm>> monitoredVms = new HashMap<>(); + private final VmBlacklist blacklist; + + JvmStatHostListener(VmInfoDAO vmInfoDAO, VmStatusChangeNotifier notifier, + ProcessUserInfoBuilder userInfoBuilder, WriterID writerId, + VmBlacklist blacklist) { + this.vmInfoDAO = vmInfoDAO; + this.notifier = notifier; + this.userInfoBuilder = userInfoBuilder; + this.writerId = writerId; + this.blacklist = blacklist; + } + + @Override + public void disconnected(HostEvent event) { + logger.warning("Disconnected from host"); + } + + @SuppressWarnings("unchecked") // Unchecked casts to (Set<Integer>). + @Override + public void vmStatusChanged(VmStatusChangeEvent event) { + MonitoredHost host = event.getMonitoredHost(); + + for (Integer newVm : (Set<Integer>) event.getStarted()) { + try { + logger.fine("New vm: " + newVm); + sendNewVM(newVm, host); + } catch (MonitorException e) { + logger.log(Level.WARNING, "error getting info for new vm " + newVm, e); + } catch (URISyntaxException e) { + logger.log(Level.WARNING, "error getting info for new vm " + newVm, e); + } + } + + for (Integer stoppedVm : (Set<Integer>) event.getTerminated()) { + try { + logger.fine("stopped vm: " + stoppedVm); + sendStoppedVM(stoppedVm, host); + } catch (URISyntaxException e) { + logger.log(Level.WARNING, "error getting info for stopped vm " + stoppedVm, e); + } catch (MonitorException e) { + logger.log(Level.WARNING, "error getting info for stopped vm " + stoppedVm, e); + } + } + } + + private void sendNewVM(Integer vmPid, MonitoredHost host) + throws MonitorException, URISyntaxException { + // Propagate any MonitorException, and do not notify Backends or remember + // VMs when we fail to extract the necessary information. + // http://icedtea.classpath.org/pipermail/thermostat/2013-November/008702.html + MonitoredVm vm = host.getMonitoredVm(host.getHostIdentifier().resolve( + new VmIdentifier(vmPid.toString()))); + if (vm != null) { + JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm); + String vmId = UUID.randomUUID().toString(); + long stopTime = Long.MIN_VALUE; + VmInfo info = createVmInfo(vmId, vmPid, stopTime, extractor); + + // Check blacklist + if (!blacklist.isBlacklisted(info.getMainClass())) { + vmInfoDAO.putVmInfo(info); + + notifier.notifyVmStatusChange(Status.VM_STARTED, vmId, vmPid); + logger.finer("Sent VM_STARTED messsage"); + + monitoredVms.put(vmPid, new Pair<>(vmId, vm)); + } + else { + logger.info("Skipping VM: " + vmPid); + } + } + } + + VmInfo createVmInfo(String vmId, Integer vmPid, long stopTime, + JvmStatDataExtractor extractor) throws MonitorException { + Map<String, String> properties = new HashMap<String, String>(); + Map<String, String> environment = InfoBuilderFactory.INSTANCE.createProcessEnvironmentBuilder().build(vmPid); + // TODO actually figure out the loaded libraries. + String[] loadedNativeLibraries = new String[0]; + ProcessUserInfo userInfo = userInfoBuilder.build(vmPid); + VmInfo info = new VmInfo(writerId.getWriterID(), vmId, vmPid, extractor.getVmStartTime(), stopTime, + extractor.getJavaVersion(), extractor.getJavaHome(), + extractor.getMainClass(), extractor.getCommandLine(), + extractor.getVmName(), extractor.getVmInfo(), extractor.getVmVersion(), extractor.getVmArguments(), + properties, environment, loadedNativeLibraries, userInfo.getUid(), userInfo.getUsername()); + return info; + } + + private void sendStoppedVM(Integer vmPid, MonitoredHost host) throws URISyntaxException, MonitorException { + + VmIdentifier resolvedVmID = host.getHostIdentifier().resolve(new VmIdentifier(vmPid.toString())); + if (resolvedVmID != null && monitoredVms.containsKey(vmPid)) { + Pair<String, MonitoredVm> vmData = monitoredVms.remove(vmPid); + + String vmId = vmData.getFirst(); + notifier.notifyVmStatusChange(Status.VM_STOPPED, vmId, vmPid); + + long stopTime = System.currentTimeMillis(); + vmInfoDAO.putVmStoppedTime(writerId.getWriterID(), vmId, stopTime); + + MonitoredVm vm = vmData.getSecond(); + vm.detach(); + } + } + + /* + * For testing purposes only. + */ + Map<Integer, Pair<String, MonitoredVm>> getMonitoredVms() { + return monitoredVms; + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/VMMonitorBackend.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,142 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal; + +import com.redhat.thermostat.backend.Backend; +import com.redhat.thermostat.backend.BaseBackend; +import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder; +import com.redhat.thermostat.common.portability.ProcessUserInfoBuilderFactory; +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.jvm.overview.agent.VmBlacklist; +import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoDAO; +import com.redhat.thermostat.storage.core.WriterID; +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.FrameworkUtil; +import sun.jvmstat.monitor.HostIdentifier; +import sun.jvmstat.monitor.MonitorException; +import sun.jvmstat.monitor.MonitoredHost; + +import java.net.URISyntaxException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + */ +@Component +@Service(value = Backend.class) +public class VMMonitorBackend extends BaseBackend { + private static final Logger logger = LoggingUtils.getLogger(VMMonitorBackend.class); + + @Reference + private VmInfoDAO vmInfoDAO; + + private VmStatusChangeNotifier notifier; + + @Reference + private WriterID writerId; + + @Reference + private VmBlacklist blacklist; + + private volatile boolean active; + + private MonitoredHost host; + private JvmStatHostListener hostListener; + + public VMMonitorBackend() { + super("VM Basic Monitor Backend", + "Monitor the system for JVM processes", + "Red Hat, Inc.", + "0.1"); + } + + @Activate + private void _activate_(BundleContext context) { + notifier = new VmStatusChangeNotifier(context); + notifier.start(); + } + + @Deactivate + private void _deactivate_() { + notifier.stop(); + } + + @Override + public synchronized boolean activate() { + try { + ProcessUserInfoBuilder userInfoBuilder = ProcessUserInfoBuilderFactory.createBuilder(); + hostListener = new JvmStatHostListener(vmInfoDAO, notifier, + userInfoBuilder, writerId, blacklist); + HostIdentifier hostId = new HostIdentifier((String) null); + host = MonitoredHost.getMonitoredHost(hostId); + host.addHostListener(hostListener); + active = true; + + } catch (MonitorException | URISyntaxException me) { + logger.log(Level.WARNING, "problems with connecting jvmstat to local machine", me); + } + + return active; + } + + @Override + public synchronized boolean deactivate() { + try { + host.removeHostListener(hostListener); + active = false; + } catch (MonitorException me) { + logger.log(Level.INFO, "something went wrong in jvmstat's listening to this host"); + } + + return !active; + } + + @Override + public synchronized boolean isActive() { + return active; + } + + @Override + public int getOrderValue() { + return ORDER_DEFAULT_GROUP; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/VmBlacklistImpl.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,79 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import com.redhat.thermostat.common.Filter; +import com.redhat.thermostat.jvm.overview.agent.VmBlacklist; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Service; + +@Component +@Service(value = VmBlacklist.class) +public class VmBlacklistImpl implements VmBlacklist { + + private final List<Filter<String>> filters; + + public VmBlacklistImpl() { + this.filters = new CopyOnWriteArrayList<>(); + } + + @Override + public void addVmFilter(Filter<String> filter) { + filters.add(filter); + } + + @Override + public void removeVmFilter(Filter<String> filter) { + filters.remove(filter); + } + + @Override + public boolean isBlacklisted(String mainClass) { + boolean result = false; + for (Filter<String> filter : filters) { + if (filter.matches(mainClass)) { + result = true; + } + } + return result; + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/VmListenerWrapper.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,126 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.common.utils.LoggingUtils; + +import com.redhat.thermostat.jvm.overview.agent.VmUpdate; +import com.redhat.thermostat.jvm.overview.agent.VmUpdateException; +import com.redhat.thermostat.jvm.overview.agent.VmUpdateListener; +import sun.jvmstat.monitor.Monitor; +import sun.jvmstat.monitor.MonitorException; +import sun.jvmstat.monitor.MonitoredVm; +import sun.jvmstat.monitor.event.MonitorStatusChangeEvent; +import sun.jvmstat.monitor.event.VmEvent; +import sun.jvmstat.monitor.event.VmListener; + +public class VmListenerWrapper implements VmListener { + + private static final Logger logger = LoggingUtils.getLogger(VmListenerWrapper.class); + // Threshold until this listener gets removed from the JVM in case of it throwing + // exceptions on countersUpdated() + private static final int EXCEPTION_THRESHOLD = 10; + private final VmUpdateListener listener; + private final MonitoredVm vm; + private final VmUpdate update; + private int exceptionCount; + + public VmListenerWrapper(VmUpdateListener listener, MonitoredVm vm) { + this.listener = listener; + this.vm = vm; + this.update = new VmUpdateImpl(this); + } + + @Override + public void monitorsUpdated(VmEvent event) { + if (!vm.equals(event.getMonitoredVm())) { + throw new AssertionError("Received change event for wrong VM"); + } + try { + listener.countersUpdated(update); + } catch (Throwable t) { + handleListenerException(t); + } + } + + private void handleListenerException(Throwable t) { + final String listenerName = listener.getClass().getName(); + if (exceptionCount < EXCEPTION_THRESHOLD) { + logger.log(Level.INFO, "VM listener " + listenerName + " threw an exception", t); + exceptionCount++; + } else { + logger.fine("Removing bad listener " + listenerName + " due to too many repeated exceptions."); + try { + vm.removeVmListener(this); + } catch (MonitorException e) { + // ignore remove failures for bad listeners + } + } + } + + @Override + public void monitorStatusChanged(MonitorStatusChangeEvent event) { + // Nothing to do here + } + + @Override + public void disconnected(VmEvent event) { + // Nothing to do here + } + + public Monitor getMonitor(String name) throws VmUpdateException { + Monitor result; + try { + result = vm.findByName(name); + } catch (MonitorException e) { + throw new VmUpdateException("Error communicating with monitored VM", e); + } + return result; + } + + /* + * For testing purposes only. + */ + public VmUpdateListener getVmUpdateListener() { + return listener; + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/VmStatusChangeNotifier.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,138 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; + +import com.redhat.thermostat.jvm.overview.agent.VmStatusListener; +import com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTracker; + +/** + * Notifies any and all {@link com.redhat.thermostat.jvm.overview.agent.VmStatusListener} registered as OSGi Services + * about VM status changes: {@link com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status#VM_STARTED} and + * {@link com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status#VM_STOPPED}. + * <p> + * Any listeners registered after a {@link com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status#VM_STARTED} + * was delivered receive a {@link com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status#VM_ACTIVE} event + * instead as an indication that a VM was started at some unknown point + * previously. + */ +public class VmStatusChangeNotifier { + + private final Object listenerLock = new Object(); + private final Map<Integer, String> activePids; + private final Map<VmStatusListener, Set<Integer>> listeners = new ConcurrentHashMap<>(); + + private final ServiceTracker tracker; + + public VmStatusChangeNotifier(BundleContext bundleContext) { + this.activePids = new HashMap<>(); + + tracker = new ServiceTracker(bundleContext, VmStatusListener.class, null) { + @Override + public VmStatusListener addingService(ServiceReference reference) { + VmStatusListener listener = (VmStatusListener) super.addingService(reference); + + synchronized (listenerLock) { + Set<Integer> notifiedAbout = new TreeSet<>(); + for (Entry<Integer, String> entry : activePids.entrySet()) { + Integer pid = entry.getKey(); + listener.vmStatusChanged(Status.VM_ACTIVE, entry.getValue(), pid); + notifiedAbout.add(pid); + } + + listeners.put(listener, notifiedAbout); + } + + return listener; + } + + @Override + public void removedService(ServiceReference reference, + Object service) { + VmStatusListener listener = (VmStatusListener) service; + listeners.remove(listener); + super.removedService(reference, service); + } + }; + } + + public void start() { + tracker.open(); + } + + public void stop() { + tracker.close(); + } + + /** + * Notify all registered listeners about a Vm status change. + * + * @param newStatus either {@link VmStatusListener.Status#VM_STARTED} or + * {@link VmStatusListener.Status#VM_STOPPED} + * @param vmId unique identifier for the VM + * @param pid process ID for the VM + */ + public void notifyVmStatusChange(VmStatusListener.Status newStatus, String vmId, int pid) { + if (newStatus == Status.VM_ACTIVE) { + throw new IllegalArgumentException("Dont pass in " + Status.VM_ACTIVE + ", that will be handled automatically"); + } + + synchronized (listenerLock) { + for (Entry<VmStatusListener, Set<Integer>> entry : listeners.entrySet()) { + entry.getKey().vmStatusChanged(newStatus, vmId, pid); + entry.getValue().add(pid); + } + + if (newStatus == Status.VM_STARTED) { + activePids.put(pid, vmId); + } else { + activePids.remove(pid); + } + } + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/VmUpdateImpl.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,79 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal; + +import com.redhat.thermostat.jvm.overview.agent.VmUpdate; +import com.redhat.thermostat.jvm.overview.agent.VmUpdateException; +import sun.jvmstat.monitor.Monitor; + +public class VmUpdateImpl implements VmUpdate { + + private VmListenerWrapper wrapper; + + public VmUpdateImpl(VmListenerWrapper wrapper) { + this.wrapper = wrapper; + } + + @Override + public Long getPerformanceCounterLong(String name) throws VmUpdateException { + return (Long) getPerformanceCounter(name); + } + + @Override + public String getPerformanceCounterString(String name) + throws VmUpdateException { + return (String) getPerformanceCounter(name); + } + + private Object getPerformanceCounter(String name) throws VmUpdateException { + Object result = null; + Monitor monitor = wrapper.getMonitor(name); + if (monitor != null) { + result = monitor.getValue(); + } + return result; + } + + /* + * For testing purposes only. + */ + VmListenerWrapper getWrapper() { + return wrapper; + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/InfoBuilderFactory.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,50 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal.model; + +import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder; +import com.redhat.thermostat.common.portability.UserNameUtil; + +/** + * Allows callers to access OS-specific builders portably + */ +public interface InfoBuilderFactory { + + InfoBuilderFactory INSTANCE = new InfoBuilderFactoryImpl(); + ProcessEnvironmentBuilder createProcessEnvironmentBuilder(); + ProcessUserInfoBuilder createProcessUserInfoBuilder(final UserNameUtil userNameUtil); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/InfoBuilderFactoryImpl.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,59 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal.model; + +import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder; +import com.redhat.thermostat.common.portability.ProcessUserInfoBuilderFactory; +import com.redhat.thermostat.common.portability.UserNameUtil; +import com.redhat.thermostat.common.portability.linux.ProcDataSource; + +/** + * Allows callers to access Windows-specific builders portably + */ +public class InfoBuilderFactoryImpl implements InfoBuilderFactory { + + public InfoBuilderFactoryImpl() { + } + + public ProcessEnvironmentBuilder createProcessEnvironmentBuilder() { + return new ProcessEnvironmentBuilderImpl(); + } + + public ProcessUserInfoBuilder createProcessUserInfoBuilder(final UserNameUtil userNameUtil) { + return ProcessUserInfoBuilderFactory.createBuilder(new ProcDataSource(), userNameUtil); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/ProcessEnvironmentBuilder.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,47 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal.model; + +import java.util.Map; + +/** + * Interface for fetching a process environment + * An environment is represented as a map of name-value pairs + */ +public interface ProcessEnvironmentBuilder { + Map<String,String> build(int pid); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/ProcessEnvironmentBuilderImpl.java Fri Jun 09 16:38:44 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal.model; + +import com.redhat.thermostat.common.portability.PortableProcess; +import com.redhat.thermostat.common.portability.PortableProcessFactory; + +import java.util.Map; + +/** + * Build process environment information via portable helper classes + */ +public class ProcessEnvironmentBuilderImpl implements ProcessEnvironmentBuilder { + + private final PortableProcess helper; + + public ProcessEnvironmentBuilderImpl() { + this(PortableProcessFactory.getInstance()); + } + + public ProcessEnvironmentBuilderImpl(PortableProcess wh) { + helper = wh; + } + + @Override + public Map<String, String> build(int pid) { + return helper.getEnvironment(pid); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/VmInfoDAO.java Fri Jun 09 16:38:44 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal.model; + +import java.util.Set; + +import com.redhat.thermostat.annotations.Service; +import com.redhat.thermostat.jvm.overview.agent.model.VmId; +import com.redhat.thermostat.jvm.overview.agent.model.VmInfo; +import com.redhat.thermostat.storage.core.AgentId; + +@Service +public interface VmInfoDAO { + + /** @return {@code null} if no information can be found */ + VmInfo getVmInfo(VmId id); + + /** + * + * @param agentId The id of host to get the VM(s) for. + * @return A set of the VmId(s). + */ + Set<VmId> getVmIds(AgentId agentId); + + void putVmInfo(VmInfo info); + + void putVmStoppedTime(String agentId, String vmId, long since); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/VmInfoDAOImpl.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,253 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal.model; + +import java.io.IOException; +import java.net.URI; +import java.util.Arrays; +import java.util.Collections; + +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoTypeAdapter.VmInfoUpdateTypeAdapter; +import com.redhat.thermostat.jvm.overview.agent.model.VmId; +import com.redhat.thermostat.jvm.overview.agent.model.VmInfo; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Service; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.HttpContentResponse; +import org.eclipse.jetty.client.HttpRequest; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.util.StringContentProvider; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpStatus; + +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.storage.core.AgentId; + +@Component +@Service(VmInfoDAO.class) +public class VmInfoDAOImpl implements VmInfoDAO { + + private final Logger logger = LoggingUtils.getLogger(VmInfoDAOImpl.class); + + private static final String GATEWAY_URL = "http://localhost:26000/api/v100"; // TODO configurable + private static final String GATEWAY_PATH = "/vm-info/systems/*/agents/"; + private static final String GATEWAY_PATH_JVM_SUFFIX = "/jvms/"; + private static final String CONTENT_TYPE = "application/json"; + + private final HttpHelper httpHelper; + private final JsonHelper jsonHelper; + + public VmInfoDAOImpl() throws Exception { + this(new HttpHelper(new HttpClient()), new JsonHelper(new VmInfoTypeAdapter(), new VmInfoUpdateTypeAdapter())); + } + + VmInfoDAOImpl(HttpHelper httpHelper, JsonHelper jsonHelper) throws Exception { + this.jsonHelper = jsonHelper; + this.httpHelper = httpHelper; + + this.httpHelper.startClient(); + } + + @Override + public VmInfo getVmInfo(final VmId id) { + return null; // TODO Remove once VM Id completer is removed + } + + @Override + public Set<VmId> getVmIds(AgentId agentId) { + return Collections.emptySet(); // TODO Remove once VM Id completer is removed + } + + @Override + public void putVmInfo(final VmInfo info) { + try { + // Encode as JSON and send as POST request + String json = jsonHelper.toJson(Arrays.asList(info)); + StringContentProvider provider = httpHelper.createContentProvider(json); + + String url = getAddURL(info.getAgentId()); + Request httpRequest = httpHelper.newRequest(url); + httpRequest.method(HttpMethod.POST); + httpRequest.content(provider, CONTENT_TYPE); + sendRequest(httpRequest); + } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) { + logger.log(Level.WARNING, "Failed to send JVM information to web gateway", e); + } + } + + @Override + public void putVmStoppedTime(final String agentId, final String vmId, final long timestamp) { + try { + // Encode as JSON and send as PUT request + VmInfoUpdate update = new VmInfoUpdate(timestamp); + String json = jsonHelper.toJson(update); + StringContentProvider provider = httpHelper.createContentProvider(json); + + String url = getUpdateURL(agentId, vmId); + Request httpRequest = httpHelper.newRequest(url); + httpRequest.method(HttpMethod.PUT); + httpRequest.content(provider, CONTENT_TYPE); + sendRequest(httpRequest); + } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) { + logger.log(Level.WARNING, "Failed to send JVM information update to web gateway", e); + } + } + + private void sendRequest(Request httpRequest) + throws InterruptedException, TimeoutException, ExecutionException, IOException { + ContentResponse resp = httpRequest.send(); + int status = resp.getStatus(); + if (status != HttpStatus.OK_200) { + throw new IOException("Gateway returned HTTP status " + String.valueOf(status) + " - " + resp.getReason()); + } + } + + private String getAddURL(String agentId) { + StringBuilder builder = buildURL(agentId); + return builder.toString(); + } + + private StringBuilder buildURL(String agentId) { + StringBuilder builder = new StringBuilder(); + builder.append(GATEWAY_URL); + builder.append(GATEWAY_PATH); + builder.append(agentId); + return builder; + } + + private String getUpdateURL(String agentId, String vmId) { + StringBuilder builder = buildURL(agentId); + builder.append(GATEWAY_PATH_JVM_SUFFIX); + builder.append(vmId); + return builder.toString(); + } + + static class VmInfoUpdate { + + private final long stoppedTime; + + VmInfoUpdate(long stoppedTime) { + this.stoppedTime = stoppedTime; + } + + long getStoppedTime() { + return stoppedTime; + } + } + + + // For testing purposes + static class JsonHelper { + + private final VmInfoTypeAdapter typeAdapter; + private final VmInfoUpdateTypeAdapter updateTypeAdapter; + + public JsonHelper(VmInfoTypeAdapter typeAdapter, VmInfoUpdateTypeAdapter updateTypeAdapter) { + this.typeAdapter = typeAdapter; + this.updateTypeAdapter = updateTypeAdapter; + } + + String toJson(List<VmInfo> infos) throws IOException { + return typeAdapter.toJson(infos); + } + + String toJson(VmInfoUpdate update) throws IOException { + return updateTypeAdapter.toJson(update); + } + + } + + // For testing purposes + static class HttpHelper { + + private final HttpClient httpClient; + + HttpHelper(HttpClient httpClient) { + this.httpClient = httpClient; + } + + void startClient() throws Exception { + httpClient.start(); + } + + StringContentProvider createContentProvider(String content) { + return new StringContentProvider(content); + } + + Request newRequest(String url) { + return new MockRequest(httpClient, URI.create(url)); + } + + } + + // FIXME This class should be removed when the web gateway has a microservice for this DAO + private static class MockRequest extends HttpRequest { + + MockRequest(HttpClient client, URI uri) { + super(client, uri); + } + + @Override + public ContentResponse send() throws InterruptedException, TimeoutException, ExecutionException { + return new MockResponse(); + } + + } + + // FIXME This class should be removed when the web gateway has a microservice for this DAO + private static class MockResponse extends HttpContentResponse { + + MockResponse() { + super(null, null, null); + } + + @Override + public int getStatus() { + return HttpStatus.OK_200; + } + + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/internal/model/VmInfoTypeAdapter.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,198 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal.model; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoDAOImpl.VmInfoUpdate; +import com.redhat.thermostat.jvm.overview.agent.model.VmInfo; + +public class VmInfoTypeAdapter extends TypeAdapter<List<VmInfo>> { + + private static final String AGENT_ID = "agentId"; + private static final String VM_ID = "vmId"; + private static final String VM_PID = "vmPid"; + private static final String JAVA_VERSION = "javaVersion"; + private static final String JAVA_HOME = "javaHome"; + private static final String MAIN_CLASS = "mainClass"; + private static final String JAVA_COMMAND_LINE = "javaCommandLine"; + private static final String VM_ARGUMENTS = "vmArguments"; + private static final String VM_NAME = "vmName"; + private static final String VM_INFO = "vmInfo"; + private static final String VM_VERSION = "vmVersion"; + private static final String PROPERTIES_AS_ARRAY = "propertiesAsArray"; + private static final String ENVIRONMENT_AS_ARRAY = "environmentAsArray"; + private static final String LOADED_NATIVE_LIBRARIES = "loadedNativeLibraries"; + private static final String START_TIME_STAMP = "startTimeStamp"; + private static final String STOP_TIME_STAMP = "stopTimeStamp"; + private static final String UID = "uid"; + private static final String USERNAME = "username"; + private static final String TYPE_LONG = "$numberLong"; + private static final String KEY = "key"; + private static final String VALUE = "value"; + + @Override + public void write(JsonWriter out, List<VmInfo> value) throws IOException { + // Request is an array of VmInfo objects + out.beginArray(); + + for (VmInfo info : value) { + writeVmInfo(out, info); + } + + out.endArray(); + } + + private void writeVmInfo(JsonWriter out, VmInfo info) throws IOException { + out.beginObject(); + + // Write each field of VmInfo as part of a JSON object + out.name(AGENT_ID); + out.value(info.getAgentId()); + out.name(VM_ID); + out.value(info.getVmId()); + out.name(VM_PID); + out.value(info.getVmPid()); + out.name(START_TIME_STAMP); + writeLong(out, info.getStartTimeStamp()); + out.name(STOP_TIME_STAMP); + writeLong(out, info.getStopTimeStamp()); + out.name(JAVA_VERSION); + out.value(info.getJavaVersion()); + out.name(JAVA_HOME); + out.value(info.getJavaHome()); + out.name(MAIN_CLASS); + out.value(info.getMainClass()); + out.name(JAVA_COMMAND_LINE); + out.value(info.getJavaCommandLine()); + out.name(VM_NAME); + out.value(info.getVmName()); + out.name(VM_ARGUMENTS); + out.value(info.getVmArguments()); + out.name(VM_INFO); + out.value(info.getVmInfo()); + out.name(VM_VERSION); + out.value(info.getVmVersion()); + out.name(PROPERTIES_AS_ARRAY); + writeStringMap(out, info.getProperties()); + out.name(ENVIRONMENT_AS_ARRAY); + writeStringMap(out, info.getEnvironment()); + out.name(LOADED_NATIVE_LIBRARIES); + writeStringArray(out, info.getLoadedNativeLibraries()); + out.name(UID); + writeLong(out, info.getUid()); + out.name(USERNAME); + out.value(info.getUsername()); + + out.endObject(); + } + + private void writeStringMap(JsonWriter out, Map<String, String> map) throws IOException { + // Write contents of Map as an array of JSON objects + out.beginArray(); + + Set<Entry<String, String>> entries = map.entrySet(); + for (Map.Entry<String, String> entry : entries) { + // Create JSON object with key and value labeled as JSON names + out.beginObject(); + out.name(KEY); + out.value(entry.getKey()); + out.name(VALUE); + out.value(entry.getValue()); + out.endObject(); + } + + out.endArray(); + } + + private void writeStringArray(JsonWriter out, String[] array) throws IOException { + // Write String[] as JSON array + out.beginArray(); + + for (String item : array) { + out.value(item); + } + + out.endArray(); + } + + private static void writeLong(JsonWriter out, long value) throws IOException { + // Write MongoDB representation of a Long + out.beginObject(); + out.name(TYPE_LONG); + out.value(String.valueOf(value)); + out.endObject(); + } + + @Override + public List<VmInfo> read(JsonReader in) throws IOException { + throw new UnsupportedOperationException(); + } + + static class VmInfoUpdateTypeAdapter extends TypeAdapter<VmInfoUpdate> { + + private static final String SET = "set"; + + @Override + public void write(JsonWriter out, VmInfoUpdate value) throws IOException { + // List fields to update as part of a JSON object with name "set" + out.beginObject(); + out.name(SET); + + out.beginObject(); + out.name(STOP_TIME_STAMP); + writeLong(out, value.getStoppedTime()); + out.endObject(); + + out.endObject(); + } + + @Override + public VmInfoUpdate read(JsonReader in) throws IOException { + throw new UnsupportedOperationException(); + } + + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/model/HostsVMsLoader.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,52 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.model; + +import com.redhat.thermostat.storage.core.HostRef; + +import java.util.Collection; + + +/** + * Provides a way to load the current hosts and VMs. + */ +public interface HostsVMsLoader { + + Collection<HostRef> getHosts(); + Collection<VmRef> getVMs(HostRef host); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/model/VmId.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,50 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.model; + +import com.redhat.thermostat.storage.core.Id; + +/** + * This class uniquely identifies a Java Virtual Machine + * + */ +public class VmId extends Id { + + public VmId(String id) { + super(id); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/model/VmInfo.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,390 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.model; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.redhat.thermostat.storage.core.Entity; +import com.redhat.thermostat.storage.core.Persist; +import com.redhat.thermostat.storage.model.AgentInformation; +import com.redhat.thermostat.storage.model.BasePojo; +import com.redhat.thermostat.storage.model.Pojo; + +@Entity +public class VmInfo extends BasePojo { + + public enum AliveStatus { + RUNNING, + EXITED, + /** + * We don't know what the status of this VM is. Possible cause: agent + * was shut down before the VM was. + */ + UNKNOWN, + } + + @Entity + public static class KeyValuePair implements Pojo { + + private String key; + private String value; + + public KeyValuePair() { + this(null, null); + } + + public KeyValuePair(String key, String value) { + this.key = key; + this.value = value; + } + + @Persist + public String getKey() { + return key; + } + + @Persist + public void setKey(String key) { + this.key = key; + } + + @Persist + public String getValue() { + return value; + } + + @Persist + public void setValue(String value) { + this.value = value; + } + + + } + + private String vmId; + private int vmPid = 0; + private long startTime = System.currentTimeMillis(); + private long stopTime = Long.MIN_VALUE; + private String javaVersion = "unknown"; + private String javaHome = "unknown"; + private String javaCommandLine = "unknown"; + private String mainClass = "unknown"; + private String vmName = "unknown"; + private String vmInfo = "unknown"; + private String vmVersion = "unknown"; + private String vmArguments = "unknown"; + private Map<String, String> properties = new HashMap<String, String>(); + private Map<String, String> environment = new HashMap<String, String>(); + private String[] loadedNativeLibraries; + private long uid; + private String username; + + public VmInfo() { + /* use defaults */ + super(null); + } + + public VmInfo(String writerId, String vmId, int vmPid, long startTime, long stopTime, + String javaVersion, String javaHome, + String mainClass, String commandLine, + String vmName, String vmInfo, String vmVersion, String vmArguments, + Map<String, String> properties, Map<String, String> environment, String[] loadedNativeLibraries, + long uid, String username) { + super(writerId); + this.vmId = vmId; + this.vmPid = vmPid; + this.startTime = startTime; + this.stopTime = stopTime; + this.javaVersion = javaVersion; + this.javaHome = javaHome; + this.mainClass = mainClass; + this.javaCommandLine = commandLine; + this.vmName = vmName; + this.vmInfo = vmInfo; + this.vmVersion = vmVersion; + this.vmArguments = vmArguments; + this.properties = properties; + this.environment = environment; + this.loadedNativeLibraries = loadedNativeLibraries; + this.uid = uid; + this.username = username; + } + + @Persist + public String getVmId() { + return vmId; + } + + @Persist + public void setVmId(String vmId) { + this.vmId = vmId; + } + + @Persist + public int getVmPid() { + return vmPid; + } + + @Persist + public void setVmPid(int vmPid) { + this.vmPid = vmPid; + } + + @Persist + public long getStartTimeStamp() { + return startTime; + } + + @Persist + public void setStartTimeStamp(long startTime) { + this.startTime = startTime; + } + + @Persist + public long getStopTimeStamp() { + return stopTime; + } + + @Persist + public void setStopTimeStamp(long stopTime) { + this.stopTime = stopTime; + } + + @Persist + public String getJavaVersion() { + return javaVersion; + } + + @Persist + public void setJavaVersion(String javaVersion) { + this.javaVersion = javaVersion; + } + + @Persist + public String getJavaHome() { + return javaHome; + } + + @Persist + public void setJavaHome(String javaHome) { + this.javaHome = javaHome; + } + + /** + * If java is invoked as {@code java -jar foo.jar}, then the main class name + * is {@code foo.jar}. + */ + @Persist + public String getMainClass() { + return mainClass; + } + + @Persist + public void setMainClass(String mainClass) { + this.mainClass = mainClass; + } + + @Persist + public String getJavaCommandLine() { + return javaCommandLine; + } + + @Persist + public void setJavaCommandLine(String javaCommandLine) { + this.javaCommandLine = javaCommandLine; + } + + @Persist + public String getVmName() { + return vmName; + } + + @Persist + public void setVmName(String vmName) { + this.vmName = vmName; + } + + @Persist + public String getVmArguments() { + return vmArguments; + } + + @Persist + public void setVmArguments(String vmArguments) { + this.vmArguments = vmArguments; + } + + @Persist + public String getVmInfo() { + return vmInfo; + } + + @Persist + public void setVmInfo(String vmInfo) { + this.vmInfo = vmInfo; + } + + @Persist + public String getVmVersion() { + return vmVersion; + } + + @Persist + public void setVmVersion(String vmVersion) { + this.vmVersion = vmVersion; + } + + /** + * @deprecated This can incorrectly show a VM as running when the actual + * status is unknown. Use {@link #isAlive(AgentInformation)} + * instead. + */ + @Deprecated + public boolean isAlive() { + return getStartTimeStamp() > getStopTimeStamp(); + } + + public AliveStatus isAlive(AgentInformation agentInfo) { + if (agentInfo.isAlive()) { + return (isAlive() ? AliveStatus.RUNNING : AliveStatus.EXITED); + } else { + return (isAlive() ? AliveStatus.UNKNOWN: AliveStatus.EXITED); + } + } + + public Map<String, String> getProperties() { + return properties; + } + + public void setProperties(Map<String, String> properties) { + this.properties = properties; + } + + @Persist + public KeyValuePair[] getPropertiesAsArray() { + return getMapAsArray(properties); + } + + @Persist + public void setPropertiesAsArray(KeyValuePair[] properties) { + this.properties = getArrayAsMap(properties); + } + + public Map<String, String> getEnvironment() { + return environment; + } + + public void setEnvironment(Map<String, String> environment) { + this.environment = environment; + } + + @Persist + public KeyValuePair[] getEnvironmentAsArray() { + return getMapAsArray(environment); + } + + @Persist + public void setEnvironmentAsArray(KeyValuePair[] environment) { + this.environment = getArrayAsMap(environment); + } + + private KeyValuePair[] getMapAsArray(Map<String, String> map) { + if (map == null) { + return null; + } + Set<String> keys = map.keySet(); + KeyValuePair[] tuples = new KeyValuePair[keys.size()]; + int i = 0; + for (String key: keys) { + tuples[i] = new KeyValuePair(key, map.get(key)); + i++; + } + return tuples; + } + + private Map<String,String> getArrayAsMap(KeyValuePair[] tuples) { + if (tuples == null) { + return null; + } + Map<String,String> map = new HashMap<>(); + for (KeyValuePair tuple : tuples) { + map.put(tuple.getKey(), tuple.getValue()); + } + return map; + } + + @Persist + public String[] getLoadedNativeLibraries() { + return loadedNativeLibraries; + } + + @Persist + public void setLoadedNativeLibraries(String[] loadedNativeLibraries) { + this.loadedNativeLibraries = loadedNativeLibraries; + } + + /** + * Returns the system user id for the owner of this JVM process, + * or -1 if an owner could not be found. + */ + @Persist + public long getUid() { + return uid; + } + + @Persist + public void setUid(long uid) { + this.uid = uid; + } + + /** + * Returns the system user name for the owner of this JVM process, + * or null if an owner could not be found. + */ + @Persist + public String getUsername() { + return username; + } + + @Persist + public void setUsername(String username) { + this.username = username; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/model/VmLatestPojoListGetter.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,92 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.model; + +import java.util.List; +import java.util.logging.Logger; + +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.storage.core.AgentId; +import com.redhat.thermostat.storage.core.Category; +import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.model.TimeStampedPojo; + +/** + * Get a {@link List} of {@link TimeStampedPojo}s newer than a given time stamp. + * + * @see VmTimeIntervalPojoListGetter + */ +public class VmLatestPojoListGetter<T extends TimeStampedPojo> { + + public static final String VM_LATEST_QUERY_FORMAT = "QUERY %s WHERE '" + + Key.AGENT_ID.getName() + "' = ?s AND '" + + Key.VM_ID.getName() + "' = ?s AND '" + + Key.TIMESTAMP.getName() + "' > ?l SORT '" + + Key.TIMESTAMP.getName() + "' DSC"; + private static final Logger logger = LoggingUtils.getLogger(VmLatestPojoListGetter.class); + + private final Category<T> cat; + private final String queryLatest; + + public VmLatestPojoListGetter(Category<T> cat) { + this.cat = cat; + this.queryLatest = String.format(VM_LATEST_QUERY_FORMAT, cat.getName()); + } + + /** + * @deprecated use {@link #getLatest(AgentId, VmId, long)} + */ + @Deprecated + public List<T> getLatest(VmRef vmRef, long since) { + return getLatest(new AgentId(vmRef.getHostRef().getAgentId()), new VmId(vmRef.getVmId()), since); + } + + public List<T> getLatest(final AgentId agentId, final VmId vmId, final long since) { + return null; + } + + // package private for tests + String getQueryLatestDesc() { + return queryLatest; + } + + public Logger getLogger() { + return logger; + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/model/VmRef.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,118 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.model; + +import com.redhat.thermostat.storage.core.HostRef; +import com.redhat.thermostat.storage.core.Ref; + +public class VmRef implements Ref { + + private final HostRef hostRef; + private final String id; + private final Integer pid; + private final String name; + + public VmRef(HostRef hostRef, String id, Integer pid, String name) { + this.hostRef = hostRef; + this.id = id; + this.pid = pid; + this.name = name; + } + + public VmRef(HostRef hostRef, VmInfo vmInfo) { + this.hostRef = hostRef; + this.id = vmInfo.getVmId(); + this.pid = vmInfo.getVmPid(); + this.name = vmInfo.getMainClass(); + } + + @Override + public String toString() { + return name; + } + + public HostRef getHostRef() { + return hostRef; + } + + public String getVmId() { + return id; + } + + public Integer getPid() { + return pid; + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (obj == this) { + return true; + } + if (obj.getClass() != this.getClass()) { + return false; + } + VmRef other = (VmRef) obj; + if (equals(this.hostRef, other.hostRef) + && equals(this.id, other.id) + && equals(this.pid, other.pid) && equals(this.name, other.name)) { + return true; + } + return false; + } + + private static boolean equals(Object obj1, Object obj2) { + return (obj1 == null && obj2 == null) || (obj1 != null && obj1.equals(obj2)); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public String getStringID() { + return id; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/main/java/com/redhat/thermostat/jvm/overview/agent/model/VmTimeIntervalPojoListGetter.java Fri Jun 09 16:38:44 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.model; + +import java.util.List; +import java.util.logging.Logger; + +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.storage.core.AgentId; +import com.redhat.thermostat.storage.core.Category; +import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.model.TimeStampedPojo; + +/** + * Get a {@link List} of {@link TimeStampedPojo}s in a given time interval + * range. + * + * @see VmLatestPojoListGetter + */ +public class VmTimeIntervalPojoListGetter<T extends TimeStampedPojo> { + + // The query for VmTimeIntervalPojoListGetter should query for since <= timestamp < to + // in order not to miss data for multiple consecutive queries of the form [a, b), [b, c), ... + // If the query were since < timestamp < to then queries of (a, b), (b, c), ... would + // result in missed data at the endpoints (b, ...) + public static final String VM_INTERVAL_QUERY_FORMAT = "QUERY %s WHERE '" + + Key.AGENT_ID.getName() + "' = ?s AND '" + + Key.VM_ID.getName() + "' = ?s AND '" + + Key.TIMESTAMP.getName() + "' >= ?l AND '" + + Key.TIMESTAMP.getName() + "' < ?l SORT '" + + Key.TIMESTAMP.getName() + "' DSC"; + + private static final Logger logger = LoggingUtils.getLogger(VmTimeIntervalPojoListGetter.class); + + private final Category<T> cat; + private final String query; + + public VmTimeIntervalPojoListGetter(Category<T> cat) { + this.cat = cat; + this.query = String.format(VM_INTERVAL_QUERY_FORMAT, cat.getName()); + } + + /** + * @deprecated use {@link #getLatest(AgentId, VmId, long, long)} + */ + @Deprecated + public List<T> getLatest(final VmRef vmRef, final long since, final long to) { + return getLatest(new AgentId(vmRef.getHostRef().getAgentId()), new VmId(vmRef.getVmId()), since, to); + } + + public List<T> getLatest(final AgentId agentId, final VmId vmId, final long since, final long to) { + return null; + } + + // package private for tests + String getQueryLatestDesc() { + return query; + } + + protected Logger getLogger() { + return logger; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/JvmStatDataExtractorTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,168 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.redhat.thermostat.jvm.overview.agent.internal.JvmStatDataExtractor; +import org.junit.Test; + +import sun.jvmstat.monitor.MonitorException; +import sun.jvmstat.monitor.MonitoredVm; +import sun.jvmstat.monitor.StringMonitor; + +public class JvmStatDataExtractorTest { + + private MonitoredVm buildStringMonitoredVm(String monitorName, String monitorReturn) throws MonitorException { + final StringMonitor monitor = mock(StringMonitor.class); + when(monitor.stringValue()).thenReturn(monitorReturn); + when(monitor.getValue()).thenReturn(monitorReturn); + MonitoredVm vm = mock(MonitoredVm.class); + when(vm.findByName(monitorName)).thenReturn(monitor); + return vm; + } + + @Test + public void testCommandLine() throws MonitorException { + final String MONITOR_NAME = "sun.rt.javaCommand"; + final String MONITOR_VALUE = "command line java"; + MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE); + + JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm); + String returned = extractor.getCommandLine(); + + verify(vm).findByName(eq(MONITOR_NAME)); + assertEquals(MONITOR_VALUE, returned); + } + + @Test + public void testMainClass() throws MonitorException { + final String MONITOR_NAME = "sun.rt.javaCommand"; + final String MONITOR_VALUE = "some.package.Main"; + MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE); + + JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm); + String returned = extractor.getMainClass(); + + verify(vm).findByName(eq(MONITOR_NAME)); + assertEquals(MONITOR_VALUE, returned); + } + + @Test + public void testJavaVersion() throws MonitorException { + final String MONITOR_NAME = "java.property.java.version"; + final String MONITOR_VALUE = "some java version"; + MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE); + + JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm); + String returned = extractor.getJavaVersion(); + + verify(vm).findByName(eq(MONITOR_NAME)); + assertEquals(MONITOR_VALUE, returned); + } + + @Test + public void testJavaHome() throws MonitorException { + final String MONITOR_NAME = "java.property.java.home"; + final String MONITOR_VALUE = "${java.home}"; + MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE); + + JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm); + String returned = extractor.getJavaHome(); + + verify(vm).findByName(eq(MONITOR_NAME)); + assertEquals(MONITOR_VALUE, returned); + } + + @Test + public void testVmName() throws MonitorException { + final String MONITOR_NAME = "java.property.java.vm.name"; + final String MONITOR_VALUE = "${vm.name}"; + MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE); + + JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm); + String returned = extractor.getVmName(); + + verify(vm).findByName(eq(MONITOR_NAME)); + assertEquals(MONITOR_VALUE, returned); + } + + @Test + public void testVmInfo() throws MonitorException { + final String MONITOR_NAME = "java.property.java.vm.info"; + final String MONITOR_VALUE = "${vm.info}"; + MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE); + + JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm); + String returned = extractor.getVmInfo(); + + verify(vm).findByName(eq(MONITOR_NAME)); + assertEquals(MONITOR_VALUE, returned); + } + + @Test + public void testVmVersion() throws MonitorException { + final String MONITOR_NAME = "java.property.java.vm.version"; + final String MONITOR_VALUE = "${vm.version}"; + MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE); + + JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm); + String returned = extractor.getVmVersion(); + + verify(vm).findByName(eq(MONITOR_NAME)); + assertEquals(MONITOR_VALUE, returned); + } + + @Test + public void testVmArguments() throws MonitorException { + final String MONITOR_NAME = "java.rt.vmArgs"; + final String MONITOR_VALUE = "${vm.arguments}"; + MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE); + + JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm); + String returned = extractor.getVmArguments(); + + verify(vm).findByName(eq(MONITOR_NAME)); + assertEquals(MONITOR_VALUE, returned); + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/VmIdTest.java Fri Jun 09 16:38:44 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent; + +import com.redhat.thermostat.jvm.overview.agent.model.VmId; +import com.redhat.thermostat.storage.core.Id; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class VmIdTest { + + protected Id fooId1; + protected Id fooId2; + protected Id barId; + + @Before + public void setup() { + fooId1 = createId("foo"); + fooId2 = createId("foo"); + barId = createId("bar"); + } + + @Test + public void testEquals() { + assertTrue(fooId1.equals(fooId1)); + assertTrue(fooId1.equals(fooId2)); + } + + @Test + public void testNotEquals() { + assertFalse(fooId1.equals(null)); + assertFalse(fooId1.equals(barId)); + } + + @Test + public void testEqualsHaveIdenticalHashcode() { + assertEquals(fooId1, fooId2); + + assertEquals(fooId1.hashCode(), fooId1.hashCode()); + assertEquals(fooId1.hashCode(), fooId2.hashCode()); + } + + protected Id createId(String id) { return new VmId(id); } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/VmListenerBackendTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,229 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.same; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.net.URISyntaxException; + +import com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status; +import org.junit.Before; +import org.junit.Test; + +import sun.jvmstat.monitor.MonitorException; + +import com.redhat.thermostat.common.internal.test.Bug; +import com.redhat.thermostat.storage.core.WriterID; + +public class VmListenerBackendTest { + private static final String VERSION = "0.0.0"; + private static final String VM_ID = "vmId"; + private static final int VM_PID = 1; + + private com.redhat.thermostat.jvm.overview.agent.VmListenerBackend backend; + private VmStatusListenerRegistrar registrar; + private VmMonitor monitor; + private VmUpdateListener listener; + private WriterID writerId; + + @Before + public void setup() { + registrar = mock(VmStatusListenerRegistrar.class); + writerId = mock(WriterID.class); + backend = new TestBackend("Test Backend", "Backend for test", "Test Co."); + monitor = mock(VmMonitor.class); + listener = mock(VmUpdateListener.class); + backend.setMonitor(monitor); + } + + @Test + public void testActivate() { + backend.initialize(writerId, registrar, VERSION); + backend.activate(); + assertTrue(backend.isActive()); + verify(registrar).register(backend); + } + + @Test + public void testActivateNoInit() { + backend.activate(); + assertFalse(backend.isActive()); + verify(registrar, never()).register(backend); + } + + @Test + public void testActivateTwice() { + backend.initialize(writerId, registrar, VERSION); + assertTrue(backend.activate()); + assertTrue(backend.isActive()); + + assertTrue(backend.activate()); + assertTrue(backend.isActive()); + } + + @Test + public void testCanNotActivateWithoutMonitor() { + backend.initialize(writerId, registrar, VERSION); + backend.setMonitor(null); + + assertFalse(backend.activate()); + assertFalse(backend.isActive()); + } + + @Test + public void testDeactivate() { + backend.initialize(writerId, registrar, VERSION); + backend.activate(); + backend.deactivate(); + verify(registrar).unregister(backend); + assertFalse(backend.isActive()); + } + + @Test + public void testDeactivateTwice() { + backend.initialize(writerId, registrar, VERSION); + backend.activate(); + + assertTrue(backend.deactivate()); + assertFalse(backend.isActive()); + assertTrue(backend.deactivate()); + } + + @Test + public void testNewVM() { + backend.initialize(writerId, registrar, VERSION); + // Should be no response if not observing new jvm. + backend.setObserveNewJvm(false); + backend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID); + verify(monitor, times(0)).handleNewVm(same(listener), same(VM_PID)); + + backend.setObserveNewJvm(true); + backend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID); + verify(monitor).handleNewVm(listener, VM_PID); + } + + /** + * createVmListener() might be plugin-supplied code. When creating the + * listener fails due to exceptions, other listeners should still continue + * to work. That is, the exception of creating one listener must not be + * propagated. + */ + @Bug(id = "3242", + summary = "Adverse Backend breaks other Backends badly ", + url = "http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=3242") + @Test + public void testNewVMCreateListenerWithExceptions() { + VmListenerBackend testBackend = new ExceptionThrowingCreateVmListenerBackend( + "Test Backend", "Backend for test", "Test Co.", VERSION); + testBackend.initialize(writerId, registrar, VERSION); + testBackend.setObserveNewJvm(true); + VmMonitor testMonitor = mock(VmMonitor.class); + testBackend.setMonitor(testMonitor); + testBackend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID); + verify(testMonitor, times(0)).handleNewVm(any(VmUpdateListener.class), any(int.class)); + } + + @Test + public void testAlreadyRunningVM() { + backend.initialize(writerId, registrar, VERSION); + backend.setObserveNewJvm(true); + backend.vmStatusChanged(Status.VM_ACTIVE, VM_ID, VM_PID); + + verify(monitor).handleNewVm(listener, VM_PID); + } + + @Test + public void testStoppedVM() throws MonitorException, URISyntaxException { + backend.initialize(writerId, registrar, VERSION); + backend.setObserveNewJvm(true); + backend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID); + backend.vmStatusChanged(Status.VM_STOPPED, VM_ID, VM_PID); + + verify(monitor).handleStoppedVm(VM_PID); + } + + @Test + public void testDeactivateUnregistersListener() throws URISyntaxException, MonitorException { + backend.initialize(writerId, registrar, VERSION); + backend.activate(); + + backend.setObserveNewJvm(true); + backend.vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID); + backend.deactivate(); + verify(monitor).removeVmListeners(); + } + + private class TestBackend extends VmListenerBackend { + + public TestBackend(String name, String description, String vendor) { + super(name, description, vendor); + } + + @Override + public int getOrderValue() { + return 0; + } + + @Override + protected VmUpdateListener createVmListener(String writerId, String vmId, int pid) { + return listener; + } + + } + + private class ExceptionThrowingCreateVmListenerBackend extends TestBackend { + + public ExceptionThrowingCreateVmListenerBackend(String name, String description, String vendor, + String version) { + super(name, description, vendor); + } + + @Override + protected VmUpdateListener createVmListener(String writerId, String vmId, int pid) { + throw new RuntimeException("createVmListener() testing!"); + } + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/VmMonitorTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,286 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import java.net.URISyntaxException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.jvm.overview.agent.internal.TestLogHandler; +import com.redhat.thermostat.jvm.overview.agent.internal.VmListenerWrapper; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import com.redhat.thermostat.common.portability.ProcessChecker; + +import sun.jvmstat.monitor.HostIdentifier; +import sun.jvmstat.monitor.MonitorException; +import sun.jvmstat.monitor.MonitoredHost; +import sun.jvmstat.monitor.MonitoredVm; +import sun.jvmstat.monitor.VmIdentifier; +import sun.jvmstat.monitor.event.VmListener; + +public class VmMonitorTest { + + private static final String PROCESS_NOT_FOUND = "Process not found"; + private static final int MONITOR_EXCEPTION_THROWING_PID = 999; + private VmMonitor monitor; + private HostIdentifier hostIdentifier; + private MonitoredHost host; + private MonitoredVm monitoredVm; + private ProcessChecker checker; + private TestLogHandler handler; + private Logger logger; + private Level savedLoggingLevel; + + @After + public void tearDown() { + if (handler != null) { + logger.removeHandler(handler); + handler = null; + } + logger.setLevel(savedLoggingLevel); + } + + @Before + public void setUp() throws Exception { + savedLoggingLevel = setupTestLoggerAndReturnOriginalLevel(); + + hostIdentifier = mock(HostIdentifier.class); + when(hostIdentifier.resolve(isA(VmIdentifier.class))).then(new Answer<VmIdentifier>() { + @Override + public VmIdentifier answer(InvocationOnMock invocation) throws Throwable { + return (VmIdentifier) invocation.getArguments()[0]; + } + }); + host = mock(MonitoredHost.class); + when(host.getHostIdentifier()).thenReturn(hostIdentifier); + + checker = mock(ProcessChecker.class); + when(checker.exists(isA(Integer.class))).thenReturn(false); + + monitoredVm = mock(MonitoredVm.class); + + monitor = new VmMonitor(checker); + monitor.setHost(host); + } + + private Level setupTestLoggerAndReturnOriginalLevel() { + logger = Logger.getLogger("com.redhat.thermostat"); + Level originalLevel = logger.getLevel(); + logger.setLevel(Level.FINEST); + handler = new TestLogHandler(MONITOR_EXCEPTION_THROWING_PID); + logger.addHandler(handler); + return originalLevel; + } + + @Test + public void testNewVM() throws MonitorException, URISyntaxException { + final int VM_PID = 1; + VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID)); + when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm); + + VmUpdateListener listener = mock(VmUpdateListener.class); + monitor.handleNewVm(listener, VM_PID); + + // Check listener registered + ArgumentCaptor<VmListenerWrapper> captor = ArgumentCaptor.forClass(VmListenerWrapper.class); + verify(monitoredVm).addVmListener(captor.capture()); + VmListenerWrapper wrapper = captor.getValue(); + assertEquals(listener, wrapper.getVmUpdateListener()); + + // Check pid map + assertTrue(monitor.getPidToDataMap().containsKey(VM_PID)); + assertEquals(wrapper, monitor.getPidToDataMap().get(VM_PID).getSecond()); + } + + /* + * English locale "Process not found". It must not matter really for this + * test. See the next test which verifies this. + */ + @Test + public void testNewVMWithProcessNotFoundDoesNotLogWarning() throws Exception { + String exceptionMsg = PROCESS_NOT_FOUND; + basicProcNotFoundTest(exceptionMsg); + } + + /* + * Random exception message as the exact message will be locale dependent. + */ + @Test + public void testNewVMWithProcessNotFoundDoesNotLogWarning2() throws Exception { + String exceptionMsg = "foo but not bar"; + basicProcNotFoundTest(exceptionMsg); + } + + private void basicProcNotFoundTest(String exceptionMsg) throws Exception { + IllegalArgumentException iae = new IllegalArgumentException(exceptionMsg); + MonitorException procNotFound = new MonitorException(iae); + assertEquals(iae, procNotFound.getCause()); + + VmIdentifier vmID = new VmIdentifier(String.valueOf(MONITOR_EXCEPTION_THROWING_PID)); + when(host.getMonitoredVm(vmID)).thenThrow(procNotFound); + VmUpdateListener listener = mock(VmUpdateListener.class); + + monitor.handleNewVm(listener, MONITOR_EXCEPTION_THROWING_PID); + assertFalse(handler.isUnableToAttachLoggedAsWarning()); + assertTrue(handler.isUnableToAttachLoggedAsFinest()); + assertFalse(handler.isUnableToAttachLoggedAsWarningUnrelated()); + } + + @Test + public void testNewVMUnrelatedCausedMonitorExceptionLogWarning() throws Exception { + MonitorException procNotFound = new MonitorException("unknown"); + + VmIdentifier vmID = new VmIdentifier(String.valueOf(MONITOR_EXCEPTION_THROWING_PID)); + when(host.getMonitoredVm(vmID)).thenThrow(procNotFound); + VmUpdateListener listener = mock(VmUpdateListener.class); + + monitor.handleNewVm(listener, MONITOR_EXCEPTION_THROWING_PID); + assertFalse(handler.isUnableToAttachLoggedAsWarning()); + assertFalse(handler.isUnableToAttachLoggedAsFinest()); + assertTrue(handler.isUnableToAttachLoggedAsWarningUnrelated()); + } + + @Test + public void testStatVMGetMonitoredVmFails() throws MonitorException { + final int VM_PID = 1; + MonitorException monitorException = new MonitorException(); + when(host.getMonitoredVm(isA(VmIdentifier.class))).thenThrow(monitorException); + + VmUpdateListener listener = mock(VmUpdateListener.class); + monitor.handleNewVm(listener, VM_PID); + + assertFalse(monitor.getPidToDataMap().containsKey(VM_PID)); + } + + @Test + public void testStoppedVM() throws MonitorException, URISyntaxException { + final int VM_PID = 1; + VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID)); + when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm); + + VmUpdateListener listener = mock(VmUpdateListener.class); + + monitor.handleNewVm(listener, VM_PID); + monitor.handleStoppedVm(VM_PID); + + // Check listener unregistered + ArgumentCaptor<VmListenerWrapper> captor = ArgumentCaptor.forClass(VmListenerWrapper.class); + verify(monitoredVm).removeVmListener(captor.capture()); + VmListenerWrapper wrapper = captor.getValue(); + assertEquals(listener, wrapper.getVmUpdateListener()); + + assertFalse(monitor.getPidToDataMap().containsKey(VM_PID)); + } + + @Test + public void testUnknownVMStopped() throws URISyntaxException, MonitorException { + final int VM_PID = 1; + VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID)); + when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm); + + monitor.handleStoppedVm(VM_PID); + + verifyNoMoreInteractions(monitoredVm); + } + + @Test + public void testErrorRemovingVmListener() throws URISyntaxException, MonitorException { + final int VM_PID = 1; + VmIdentifier VM_ID = new VmIdentifier(String.valueOf(VM_PID)); + when(host.getMonitoredVm(VM_ID)).thenReturn(monitoredVm); + + MonitorException monitorException = new MonitorException(); + doThrow(monitorException).when(monitoredVm).removeVmListener(any(VmListener.class)); + + VmUpdateListener listener = mock(VmUpdateListener.class); + monitor.handleNewVm(listener, VM_PID); + monitor.handleStoppedVm(VM_PID); + + verify(monitoredVm).detach(); + } + + @Test + public void testRemoveAllListeners() throws URISyntaxException, MonitorException { + final int VM_PID1 = 1; + final int VM_PID2 = 2; + + VmIdentifier VM_ID1 = new VmIdentifier(String.valueOf(VM_PID1)); + when(host.getMonitoredVm(VM_ID1)).thenReturn(monitoredVm); + + MonitoredVm monitoredVm2 = mock(MonitoredVm.class); + VmIdentifier VM_ID2 = new VmIdentifier(String.valueOf(VM_PID2)); + when(host.getMonitoredVm(VM_ID2)).thenReturn(monitoredVm2); + + VmUpdateListener listener1 = mock(VmUpdateListener.class); + VmUpdateListener listener2 = mock(VmUpdateListener.class); + monitor.handleNewVm(listener1, VM_PID1); + monitor.handleNewVm(listener2, VM_PID2); + + monitor.removeVmListeners(); + + ArgumentCaptor<VmListenerWrapper> captor1 = ArgumentCaptor.forClass(VmListenerWrapper.class); + verify(monitoredVm).removeVmListener(captor1.capture()); + VmListenerWrapper wrapper1 = captor1.getValue(); + assertEquals(listener1, wrapper1.getVmUpdateListener()); + + ArgumentCaptor<VmListenerWrapper> captor2 = ArgumentCaptor.forClass(VmListenerWrapper.class); + verify(monitoredVm2).removeVmListener(captor2.capture()); + VmListenerWrapper wrapper2 = captor2.getValue(); + assertEquals(listener2, wrapper2.getVmUpdateListener()); + + assertEquals(0, monitor.getPidToDataMap().size()); + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/VmPollingBackendTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,274 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ScheduledExecutorService; + +import com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status; +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.common.Version; +import com.redhat.thermostat.common.internal.test.Bug; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class VmPollingBackendTest { + + private VmPollingBackend backend; + private ScheduledExecutorService mockExecutor; + private VmStatusListenerRegistrar mockRegistrar; + + @Before + public void setUp() { + mockExecutor = mock(ScheduledExecutorService.class); + Version mockVersion = mock(Version.class); + when(mockVersion.getVersionNumber()).thenReturn("backend-version"); + mockRegistrar = mock(VmStatusListenerRegistrar.class); + backend = new VmPollingBackend("backend-name", "backend-description", + "backend-vendor", mockVersion, mockExecutor, mockRegistrar) { + @Override + public int getOrderValue() { + return 0; // Doesn't matter, not being tested. + } + }; + if (!backend.getObserveNewJvm()) { + /* At time of writing, default is true. This is + * inherited from parent PollingBackend. In case + * default changes: + */ + backend.setObserveNewJvm(true); + } + } + + /** + * If an action throws exceptions repeatedly, that action shall get + * disabled/unregistered. + */ + @Bug(id = "3242", + summary = "Adverse Backend breaks other Backends badly ", + url = "http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=3242") + @Test + public void testDoScheduledActionsWithExceptions() { + final int beyondExceptionThreshold = 13; // anything beyond 10 will do + String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2"; + int pid1 = 123, pid2 = 456; + backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1); + backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2); + BadVmPollingAction badAction = new BadVmPollingAction(); + backend.registerAction(badAction); + for (int i = 0; i < beyondExceptionThreshold; i++) { + backend.doScheduledActions(); + } + + // The exceptions thrown for one vmID might disable the action + // for *all* other vmIDs too. So the call count for one of the + // vmIDs is actually 9, whereas the other one must have reached + // the threshold count of 10. + int callCountVm1 = badAction.getCallCount(vmId1); + int callCountVm2 = badAction.getCallCount(vmId2); + int minCallCount = Math.min(callCountVm2, callCountVm1); + int maxCallCount = Math.max(callCountVm1, callCountVm2); + assertEquals("Must not be called beyond exception threshold", + 10, maxCallCount); + assertEquals("Other action's exception cancels globally", + 9, minCallCount); + } + + @Test + public void verifyCustomActivateRegistersListener() { + backend.preActivate(); + verify(mockRegistrar).register(backend); + } + + @Test + public void verifyCustomDeactivateUnregistersListener() { + backend.postDeactivate(); + verify(mockRegistrar).unregister(backend); + } + + @Test + public void verifyRegisteredActionPerformed() { + String vmId = "test-vm-id"; + int pid = 123; + backend.vmStatusChanged(Status.VM_ACTIVE, vmId, pid); + VmPollingAction action = mock(VmPollingAction.class); + backend.registerAction(action); + backend.doScheduledActions(); + + verify(action).run(eq(vmId), eq(pid)); + } + + @Test + public void verifyMultipleRegisteredActionsPerformed() { + String vmId = "test-vm-id"; + int pid = 123; + backend.vmStatusChanged(Status.VM_ACTIVE, vmId, pid); + VmPollingAction action1 = mock(VmPollingAction.class); + VmPollingAction action2 = mock(VmPollingAction.class); + backend.registerAction(action1); + backend.registerAction(action2); + backend.doScheduledActions(); + + verify(action1).run(eq(vmId), eq(pid)); + verify(action2).run(eq(vmId), eq(pid)); + } + + @Test + public void verifyActionsPerformedOnMultipleVms() { + String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2"; + int pid1 = 123, pid2 = 456; + backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1); + backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2); + VmPollingAction action = mock(VmPollingAction.class); + backend.registerAction(action); + backend.doScheduledActions(); + + verify(action).run(eq(vmId1), eq(pid1)); + verify(action).run(eq(vmId2), eq(pid2)); + } + + @Test + public void verifyMultipleRegisteredActionsPerformedOnMultipleVms() { + String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2"; + int pid1 = 123, pid2 = 456; + backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1); + backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2); + VmPollingAction action1 = mock(VmPollingAction.class); + VmPollingAction action2 = mock(VmPollingAction.class); + backend.registerAction(action1); + backend.registerAction(action2); + backend.doScheduledActions(); + + verify(action1).run(eq(vmId1), eq(pid1)); + verify(action1).run(eq(vmId2), eq(pid2)); + verify(action2).run(eq(vmId1), eq(pid1)); + verify(action2).run(eq(vmId2), eq(pid2)); + } + + @Test + public void verifyUnregisteredActionNotPerformed() { + String vmId = "test-vm-id"; + int pid = 123; + backend.vmStatusChanged(Status.VM_ACTIVE, vmId, pid); + VmPollingAction action1 = mock(VmPollingAction.class); + VmPollingAction action2 = mock(VmPollingAction.class); + backend.registerAction(action1); + backend.registerAction(action2); + backend.doScheduledActions(); // Triggers both + backend.unregisterAction(action1); + backend.doScheduledActions(); // Triggers only action2 + + verify(action1, times(1)).run(eq(vmId), eq(pid)); + verify(action2, times(2)).run(eq(vmId), eq(pid)); + } + + @Test + public void verifyVmStatusChangedStartedAndActiveResultInPolling() { + String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2"; + int pid1 = 123, pid2 = 456; + backend.vmStatusChanged(Status.VM_STARTED, vmId1, pid1); + backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2); + VmPollingAction action = mock(VmPollingAction.class); + backend.registerAction(action); + backend.doScheduledActions(); + + verify(action).run(eq(vmId1), eq(pid1)); + verify(action).run(eq(vmId2), eq(pid2)); + } + + @Test + public void verifyVmStatusChangedStopsResultsInNoMorePolling() { + String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2"; + int pid1 = 123, pid2 = 456; + backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1); + backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2); + VmPollingAction action = mock(VmPollingAction.class); + backend.registerAction(action); + backend.doScheduledActions(); // Triggers for both vms + backend.vmStatusChanged(Status.VM_STOPPED, vmId1, pid1); + backend.doScheduledActions(); // Triggers only for vm2 + + verify(action, times(1)).run(eq(vmId1), eq(pid1)); + verify(action, times(2)).run(eq(vmId2), eq(pid2)); + } + + @Test + public void verifyGetSetObserveNewJvmWorksAsExpected() { + String vmId1 = "test-vm-id1", vmId2 = "test-vm-id2"; + int pid1 = 123, pid2 = 456; + backend.vmStatusChanged(Status.VM_ACTIVE, vmId1, pid1); + backend.setObserveNewJvm(false); + backend.vmStatusChanged(Status.VM_ACTIVE, vmId2, pid2); // Should be ignored. + VmPollingAction action = mock(VmPollingAction.class); + backend.registerAction(action); + backend.doScheduledActions(); + + verify(action).run(eq(vmId1), eq(pid1)); + verify(action, never()).run(eq(vmId2), eq(pid2)); + } + + private static class BadVmPollingAction implements VmPollingAction { + + private final Map<String, Integer> callCounts = new HashMap<>(); + + @Override + public void run(String vmId, int pid) { + Integer currCount = callCounts.remove(vmId); + if (currCount == null) { + currCount = Integer.valueOf(1); + } else { + currCount++; + } + callCounts.put(vmId, Integer.valueOf(currCount)); + throw new RuntimeException("doScheduledActions() testing!"); + } + + private Integer getCallCount(String vmId) { + return callCounts.get(vmId); + } + + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/VmStatusListenerRegistrarTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,75 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +import org.junit.Test; + +import com.redhat.thermostat.testutils.StubBundleContext; + +public class VmStatusListenerRegistrarTest { + + @Test + public void testRegister() { + StubBundleContext context = new StubBundleContext(); + VmStatusListener listener = mock(VmStatusListener.class); + + VmStatusListenerRegistrar registerer = new VmStatusListenerRegistrar(context); + registerer.register(listener); + + assertTrue(context.isServiceRegistered(VmStatusListener.class.getName(), listener.getClass())); + assertEquals(1, context.getAllServices().size()); + } + + @Test + public void testUnregister() { + StubBundleContext context = new StubBundleContext(); + VmStatusListener listener = mock(VmStatusListener.class); + + VmStatusListenerRegistrar registerer = new VmStatusListenerRegistrar(context); + registerer.register(listener); + registerer.unregister(listener); + + assertFalse(context.isServiceRegistered(VmStatusListener.class.getName(), listener.getClass())); + assertEquals(0, context.getAllServices().size()); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/VmUpdateImplTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,125 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import com.redhat.thermostat.jvm.overview.agent.internal.VmListenerWrapper; +import com.redhat.thermostat.jvm.overview.agent.internal.VmUpdateImpl; +import org.junit.Before; +import org.junit.Test; + +import sun.jvmstat.monitor.Monitor; + +public class VmUpdateImplTest { + + private VmUpdateImpl update; + private VmListenerWrapper wrapper; + + @Before + public void setUp() throws Exception { + wrapper = mock(VmListenerWrapper.class); + update = new VmUpdateImpl(wrapper); + } + + @Test + public void testGetPerformanceCounterLong() throws VmUpdateException { + final String counter = "myCounter"; + final Long value = 9001L; + Monitor monitor = mock(Monitor.class); + when(monitor.getValue()).thenReturn(value); + when(wrapper.getMonitor(counter)).thenReturn(monitor); + + Long result = update.getPerformanceCounterLong(counter); + assertEquals(value, result); + } + + @Test(expected=ClassCastException.class) + public void testGetPerformanceCounterLongBadType() throws VmUpdateException { + final String counter = "myCounter"; + final String value = "myValue"; + Monitor monitor = mock(Monitor.class); + when(monitor.getValue()).thenReturn(value); + when(wrapper.getMonitor(counter)).thenReturn(monitor); + + update.getPerformanceCounterLong(counter); + } + + @Test + public void testGetPerformanceCounterLongNoCounter() throws VmUpdateException { + final String counter = "myCounter"; + when(wrapper.getMonitor(counter)).thenReturn(null); + + Long result = update.getPerformanceCounterLong(counter); + assertNull(result); + } + + @Test + public void testGetPerformanceCounterString() throws VmUpdateException { + final String counter = "myCounter"; + final String value = "myValue"; + Monitor monitor = mock(Monitor.class); + when(monitor.getValue()).thenReturn(value); + when(wrapper.getMonitor(counter)).thenReturn(monitor); + + String result = update.getPerformanceCounterString(counter); + assertEquals(value, result); + } + + @Test(expected=ClassCastException.class) + public void testGetPerformanceCounterStringBadType() throws VmUpdateException { + final String counter = "myCounter"; + final Long value = 9001L; + Monitor monitor = mock(Monitor.class); + when(monitor.getValue()).thenReturn(value); + when(wrapper.getMonitor(counter)).thenReturn(monitor); + + update.getPerformanceCounterString(counter); + } + + @Test + public void testGetPerformanceCounterStringNoCounter() throws VmUpdateException { + final String counter = "myCounter"; + when(wrapper.getMonitor(counter)).thenReturn(null); + + String result = update.getPerformanceCounterString(counter); + assertNull(result); + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/JvmStatHostListenerTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,277 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.AdditionalMatchers.not; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import com.redhat.thermostat.jvm.overview.agent.VmBlacklist; +import com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status; +import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoDAO; +import com.redhat.thermostat.jvm.overview.agent.model.VmInfo; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.common.portability.ProcessUserInfo; +import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder; +import com.redhat.thermostat.storage.core.WriterID; + +import sun.jvmstat.monitor.HostIdentifier; +import sun.jvmstat.monitor.Monitor; +import sun.jvmstat.monitor.MonitorException; +import sun.jvmstat.monitor.MonitoredHost; +import sun.jvmstat.monitor.MonitoredVm; +import sun.jvmstat.monitor.StringMonitor; +import sun.jvmstat.monitor.VmIdentifier; +import sun.jvmstat.monitor.event.VmStatusChangeEvent; + +public class JvmStatHostListenerTest { + + private static String INFO_CMDLINE = "/path/to/executable command line args"; + private static String INFO_JAVAHOME = "/path/to/java"; + private static String INFO_JAVAVER = "1.9001"; + private static String INFO_MAINCLASS = "MyMainClass"; + private static String INFO_VMARGS = "-Xarg1 -Xarg2"; + private static String INFO_VMINFO = "Info"; + private static String INFO_VMNAME = "MyJVM"; + private static String INFO_VMVER = "90.01"; + private static long INFO_VMUSERID = 2000; + private static String INFO_VMUSERNAME = "User"; + private static final long INFO_STARTTIME = Long.MIN_VALUE; + + private JvmStatHostListener hostListener; + private MonitoredHost host; + private MonitoredVm monitoredVm1; + private MonitoredVm monitoredVm2; + private JvmStatDataExtractor extractor; + private VmInfoDAO vmInfoDAO; + private VmStatusChangeNotifier notifier; + private VmBlacklist blacklist; + + @Before + public void setup() throws MonitorException, URISyntaxException { + vmInfoDAO = mock(VmInfoDAO.class); + notifier = mock(VmStatusChangeNotifier.class); + + ProcessUserInfoBuilder userInfoBuilder = mock(ProcessUserInfoBuilder.class); + ProcessUserInfo userInfo = new ProcessUserInfo(INFO_VMUSERID, INFO_VMUSERNAME); + when(userInfoBuilder.build(any(int.class))).thenReturn(userInfo); + + WriterID id = mock(WriterID.class); + blacklist = mock(VmBlacklist.class); + hostListener = new JvmStatHostListener(vmInfoDAO, notifier, userInfoBuilder, id, blacklist); + + host = mock(MonitoredHost.class); + HostIdentifier hostId = mock(HostIdentifier.class); + monitoredVm1 = mock(MonitoredVm.class); + monitoredVm2 = mock(MonitoredVm.class); + StringMonitor monitor = mock(StringMonitor.class); + Monitor monitor2 = mock(Monitor.class); + VmIdentifier vmId1 = new VmIdentifier("1"); + VmIdentifier vmId2 = new VmIdentifier("2"); + + when(monitor2.getValue()).thenReturn(100l); + when(host.getHostIdentifier()).thenReturn(hostId); + when(host.getMonitoredVm(eq(vmId1))).thenReturn(monitoredVm1); + when(host.getMonitoredVm(eq(vmId2))).thenReturn(monitoredVm2); + when(hostId.resolve(eq(vmId1))).thenReturn(vmId1); + when(hostId.resolve(eq(vmId2))).thenReturn(vmId2); + when(monitoredVm1.findByName("sun.rt.vmInitDoneTime")).thenReturn(monitor2); + when(monitoredVm2.findByName("sun.rt.vmInitDoneTime")).thenReturn(monitor2); + when(monitoredVm1.findByName(not(eq("sun.rt.vmInitDoneTime")))).thenReturn(monitor); + when(monitoredVm2.findByName(not(eq("sun.rt.vmInitDoneTime")))).thenReturn(monitor); + when(monitor.stringValue()).thenReturn("test"); + when(monitor.getValue()).thenReturn("test"); + extractor = mock(JvmStatDataExtractor.class); + + when(extractor.getCommandLine()).thenReturn(INFO_CMDLINE); + when(extractor.getJavaHome()).thenReturn(INFO_JAVAHOME); + when(extractor.getJavaVersion()).thenReturn(INFO_JAVAVER); + when(extractor.getMainClass()).thenReturn(INFO_MAINCLASS); + when(extractor.getVmArguments()).thenReturn(INFO_VMARGS); + when(extractor.getVmInfo()).thenReturn(INFO_VMINFO); + when(extractor.getVmName()).thenReturn(INFO_VMNAME); + when(extractor.getVmVersion()).thenReturn(INFO_VMVER); + when(extractor.getVmStartTime()).thenReturn(INFO_STARTTIME); + } + + @Test + public void testNewVM() throws InterruptedException, MonitorException { + startVMs(); + + assertTrue(hostListener.getMonitoredVms().containsKey(1)); + assertTrue(hostListener.getMonitoredVms().containsKey(2)); + assertEquals(monitoredVm1, hostListener.getMonitoredVms().get(1).getSecond()); + assertEquals(monitoredVm2, hostListener.getMonitoredVms().get(2).getSecond()); + + // Check valid UUIDs + UUID uuid1 = UUID.fromString(hostListener.getMonitoredVms().get(1).getFirst()); + UUID uuid2 = UUID.fromString(hostListener.getMonitoredVms().get(2).getFirst()); + assertFalse(uuid1.equals(uuid2)); + + verify(notifier, times(2)).notifyVmStatusChange(eq(Status.VM_STARTED), anyString(), (isA(Integer.class))); + } + + @Test + public void testNewVMBlackListed() throws InterruptedException, MonitorException { + when(blacklist.isBlacklisted(anyString())).thenReturn(true).thenReturn(false); + startVMs(); + + assertFalse(hostListener.getMonitoredVms().containsKey(1)); + assertTrue(hostListener.getMonitoredVms().containsKey(2)); + assertEquals(monitoredVm2, hostListener.getMonitoredVms().get(2).getSecond()); + + UUID uuid = UUID.fromString(hostListener.getMonitoredVms().get(2).getFirst()); + verify(notifier).notifyVmStatusChange(eq(Status.VM_STARTED), eq(uuid.toString()), (isA(Integer.class))); + } + + @Test + public void testStoppedVM() throws InterruptedException, MonitorException { + final Set<Integer> stopped = new HashSet<>(); + stopped.add(1); + + startVMs(); + + // Trigger a change event + VmStatusChangeEvent event = mock(VmStatusChangeEvent.class); + when(event.getMonitoredHost()).thenReturn(host); + when(event.getStarted()).thenReturn(Collections.<Integer>emptySet()); + when(event.getTerminated()).thenReturn(stopped); + hostListener.vmStatusChanged(event); + + // Ensure only 1 removed + assertFalse(hostListener.getMonitoredVms().containsKey(1)); + assertTrue(hostListener.getMonitoredVms().containsKey(2)); + assertEquals(monitoredVm2, hostListener.getMonitoredVms().get(2).getSecond()); + + verify(notifier).notifyVmStatusChange(eq(Status.VM_STOPPED), anyString(), (isA(Integer.class))); + + } + + @Test + public void testReusedPid() throws MonitorException { + final Set<Integer> started = new HashSet<>(); + started.add(1); + // Start VM + VmStatusChangeEvent event = mock(VmStatusChangeEvent.class); + when(event.getMonitoredHost()).thenReturn(host); + when(event.getStarted()).thenReturn(started); + when(event.getTerminated()).thenReturn(Collections.<Integer>emptySet()); + hostListener.vmStatusChanged(event); + + ArgumentCaptor<String> vmIdCaptor = ArgumentCaptor.forClass(String.class); + + // Stop VM + event = mock(VmStatusChangeEvent.class); + when(event.getMonitoredHost()).thenReturn(host); + when(event.getStarted()).thenReturn(Collections.<Integer>emptySet()); + when(event.getTerminated()).thenReturn(started); + hostListener.vmStatusChanged(event); + + // Start new VM + event = mock(VmStatusChangeEvent.class); + when(event.getMonitoredHost()).thenReturn(host); + when(event.getStarted()).thenReturn(started); + when(event.getTerminated()).thenReturn(Collections.<Integer>emptySet()); + hostListener.vmStatusChanged(event); + + verify(notifier, times(2)).notifyVmStatusChange(eq(Status.VM_STARTED), vmIdCaptor.capture(), eq(1)); + List<String> vmIds = vmIdCaptor.getAllValues(); + + assertEquals(2, vmIds.size()); + String vmId1 = vmIds.get(0); + String vmId2 = vmIds.get(1); + assertNotNull(vmId1); + assertNotNull(vmId2); + assertFalse(vmId1.equals(vmId2)); + } + + private void startVMs() throws InterruptedException, MonitorException { + final Set<Integer> started = new HashSet<>(); + started.add(1); + started.add(2); + + // Trigger a change event + VmStatusChangeEvent event = mock(VmStatusChangeEvent.class); + when(event.getMonitoredHost()).thenReturn(host); + when(event.getStarted()).thenReturn(started); + when(event.getTerminated()).thenReturn(Collections.<Integer>emptySet()); + hostListener.vmStatusChanged(event); + } + + @Test + public void testCreateVmInfo() throws MonitorException { + final String INFO_ID = "vmId"; + final int INFO_PID = 1; + final long INFO_STOPTIME = Long.MAX_VALUE; + VmInfo info = hostListener.createVmInfo(INFO_ID, INFO_PID, INFO_STOPTIME, extractor); + + assertEquals(INFO_PID, info.getVmPid()); + assertEquals(INFO_STARTTIME, info.getStartTimeStamp()); + assertEquals(INFO_STOPTIME, info.getStopTimeStamp()); + assertEquals(INFO_CMDLINE, info.getJavaCommandLine()); + assertEquals(INFO_JAVAHOME, info.getJavaHome()); + assertEquals(INFO_JAVAVER, info.getJavaVersion()); + assertEquals(INFO_MAINCLASS, info.getMainClass()); + assertEquals(INFO_VMARGS, info.getVmArguments()); + assertEquals(INFO_VMINFO, info.getVmInfo()); + assertEquals(INFO_VMNAME, info.getVmName()); + assertEquals(INFO_VMVER, info.getVmVersion()); + assertEquals(INFO_VMUSERID, info.getUid()); + assertEquals(INFO_VMUSERNAME, info.getUsername()); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/ProcessEnvironmentBuilderTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,103 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal; + +import com.redhat.thermostat.common.portability.PortableProcess; +import com.redhat.thermostat.jvm.overview.agent.internal.model.ProcessEnvironmentBuilder; +import com.redhat.thermostat.jvm.overview.agent.internal.model.ProcessEnvironmentBuilderImpl; +import com.redhat.thermostat.shared.config.OS; + +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * test windows process env builder + */ +public class ProcessEnvironmentBuilderTest { + + private PortableProcess whelp; + + private static final int FAKE_PID = 4567; + private static final String PATH_KEY = "PATH"; + private static final String FAKE_PATH = "testpath"; + + private static final Map<String,String> goodMap = new HashMap<>(); + + @Before + public void setup() { + whelp = mock(PortableProcess.class); + goodMap.put(PATH_KEY, FAKE_PATH); + when(whelp.getEnvironment(anyInt())).thenReturn(null); + when(whelp.getEnvironment(eq(FAKE_PID))).thenReturn(goodMap); + } + + @Test + public void testSimpleBuild() { + Assume.assumeTrue(OS.IS_WINDOWS); + final Map<String,String> info = new ProcessEnvironmentBuilderImpl().build(FAKE_PID); + assertNotNull(info); + } + + @Test + public void testGetInfoFromGoodPid() { + final ProcessEnvironmentBuilder ib = new ProcessEnvironmentBuilderImpl(whelp); + final Map<String,String> info = ib.build(FAKE_PID); + assertFalse(info.isEmpty()); + assertTrue(info.containsKey(PATH_KEY)); + assertEquals(FAKE_PATH, info.get(PATH_KEY)); + } + + @Test + public void testGetInfoFromBadPid() { + final ProcessEnvironmentBuilder ib = new ProcessEnvironmentBuilderImpl(whelp); + final Map<String,String> info = ib.build(FAKE_PID+1); + assertTrue(info == null || info.isEmpty()); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/TestLogHandler.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,107 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal; + +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; + +/* + * Test log handler used for VmMonitor log testing. + */ +public class TestLogHandler extends Handler { + + private static final String PROCESS_NOT_FOUND = "Process not found"; + private static final String EXPECTED_UNABLE_TO_ATTACH_PROC_NOT_FOUND_FMT = + "Tried to attach to a process which no longer exists. Pid was %d"; + private static final String EXPECTED_UNABLE_TO_ATTACH_MSG_FMT = + "unable to attach to vm %d"; + private boolean unableToAttachLoggedWarning; + private boolean unableToAttachLoggedFinest; + private final String unableToAttachMsg; + private final String procNotFoundMsg; + + public TestLogHandler(int pid) { + unableToAttachMsg = String.format(EXPECTED_UNABLE_TO_ATTACH_MSG_FMT, pid); + procNotFoundMsg = String.format(EXPECTED_UNABLE_TO_ATTACH_PROC_NOT_FOUND_FMT, pid); + } + + @Override + public void publish(LogRecord record) { + String logMessage = record.getMessage(); + if (record.getLevel().intValue() >= Level.WARNING.intValue() && + logMessage.equals(unableToAttachMsg)) { + unableToAttachLoggedWarning = diagnoseRecord(record); + } + if (record.getLevel().intValue() == Level.FINEST.intValue() && + logMessage.equals(procNotFoundMsg)) { + unableToAttachLoggedFinest = diagnoseRecord(record); + } + } + + private boolean diagnoseRecord(LogRecord record) { + Throwable thrown = record.getThrown(); + if (thrown != null && thrown.getCause() instanceof IllegalArgumentException) { + return true; + } + return false; + } + + @Override + public void flush() { + // nothing + } + + @Override + public void close() throws SecurityException { + // nothing + } + + public boolean isUnableToAttachLoggedAsWarning() { + return unableToAttachLoggedWarning; + } + + public boolean isUnableToAttachLoggedAsWarningUnrelated() { + return !unableToAttachLoggedWarning && !unableToAttachLoggedFinest; + } + + public boolean isUnableToAttachLoggedAsFinest() { + return unableToAttachLoggedFinest; + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/VmListenerWrapperTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,154 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.redhat.thermostat.jvm.overview.agent.VmUpdate; +import com.redhat.thermostat.jvm.overview.agent.VmUpdateException; +import com.redhat.thermostat.jvm.overview.agent.VmUpdateListener; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.common.internal.test.Bug; + +import sun.jvmstat.monitor.Monitor; +import sun.jvmstat.monitor.MonitorException; +import sun.jvmstat.monitor.MonitoredVm; +import sun.jvmstat.monitor.event.VmEvent; + +public class VmListenerWrapperTest { + + private VmListenerWrapper wrapper; + private MonitoredVm monitoredVm; + private VmUpdateListener listener; + + @Before + public void setUp() throws Exception { + listener = mock(VmUpdateListener.class); + monitoredVm = mock(MonitoredVm.class); + wrapper = new VmListenerWrapper(listener, monitoredVm); + } + + /** + * Verify that a bad listener which throws exceptions gets removed + * from the JVM beyond a threshold. + * @throws MonitorException + */ + @Bug(id = "3242", + summary = "Adverse Backend breaks other Backends badly ", + url = "http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=3242") + @Test + public void testMonitorsUpdatedListenerExceptions() throws MonitorException { + final int beyondThresholdLimit = 11; + VmUpdateListener badListener = new VmUpdateListener() { + @Override + public void countersUpdated(VmUpdate update) { + throw new RuntimeException("countersUpdated() testing!"); + } + }; + VmListenerWrapper vmListenerWrapper = new VmListenerWrapper(badListener, monitoredVm); + VmEvent event = mock(VmEvent.class); + for (int i = 0; i < beyondThresholdLimit; i++) { + when(event.getMonitoredVm()).thenReturn(monitoredVm); + + vmListenerWrapper.monitorsUpdated(event); + + } + verify(monitoredVm, times(1)).removeVmListener(vmListenerWrapper); + } + + @Test + public void testMonitorsUpdated() { + VmEvent event = mock(VmEvent.class); + when(event.getMonitoredVm()).thenReturn(monitoredVm); + + wrapper.monitorsUpdated(event); + + ArgumentCaptor<VmUpdateImpl> captor = ArgumentCaptor.forClass(VmUpdateImpl.class); + verify(listener).countersUpdated(captor.capture()); + VmUpdateImpl update = captor.getValue(); + assertEquals(wrapper, update.getWrapper()); + } + + @Test(expected=AssertionError.class) + public void testMonitorsUpdatedWrongVm() { + VmEvent event = mock(VmEvent.class); + MonitoredVm badVm = mock(MonitoredVm.class); + when(event.getMonitoredVm()).thenReturn(badVm); + + wrapper.monitorsUpdated(event); + } + + @Test + public void testGetCounter() throws MonitorException, VmUpdateException { + final String counter = "myCounter"; + + Monitor monitor = mock(Monitor.class); + when(monitoredVm.findByName(counter)).thenReturn(monitor); + + Monitor result = wrapper.getMonitor(counter); + assertEquals(monitor, result); + } + + @Test + public void testGetCounterNotFound() throws MonitorException, VmUpdateException { + final String counter = "myCounter"; + + when(monitoredVm.findByName(counter)).thenReturn(null); + + Monitor result = wrapper.getMonitor(counter); + assertNull(result); + } + + @Test(expected=VmUpdateException.class) + public void testGetCounterError() throws MonitorException, VmUpdateException { + final String counter = "myCounter"; + + when(monitoredVm.findByName(counter)).thenThrow(new MonitorException()); + + wrapper.getMonitor(counter); + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/VmStatusChangeNotifierTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,206 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal; + +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import java.util.ConcurrentModificationException; + +import com.redhat.thermostat.jvm.overview.agent.VmStatusListener; +import com.redhat.thermostat.jvm.overview.agent.VmStatusListener.Status; +import org.junit.Test; +import org.osgi.framework.BundleContext; + +import com.redhat.thermostat.testutils.StubBundleContext; + +public class VmStatusChangeNotifierTest { + + @Test + public void verifyWorksWithoutAnyListeners() { + final String VM_ID = "vmId"; + final int VM_PID = 2; + StubBundleContext bundleContext = new StubBundleContext(); + + VmStatusChangeNotifier notifier = new VmStatusChangeNotifier(bundleContext); + notifier.start(); + notifier.notifyVmStatusChange(Status.VM_STARTED, VM_ID, VM_PID); + + notifier.notifyVmStatusChange(Status.VM_STOPPED, VM_ID, VM_PID); + } + + @Test + public void verifyAllListenersAreNotified() { + final String VM_ID = "vmId"; + final int VM_PID = 2; + StubBundleContext bundleContext = new StubBundleContext(); + + VmStatusListener listener = mock(VmStatusListener.class); + bundleContext.registerService(VmStatusListener.class, listener, null); + + VmStatusChangeNotifier notifier = new VmStatusChangeNotifier(bundleContext); + notifier.start(); + notifier.notifyVmStatusChange(Status.VM_STARTED, VM_ID, VM_PID); + + verify(listener).vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID); + + notifier.notifyVmStatusChange(Status.VM_STOPPED, VM_ID, VM_PID); + + verify(listener).vmStatusChanged(Status.VM_STOPPED, VM_ID, VM_PID); + } + + @Test + public void verifyListenersAddedAfterVmStartRecieveVmActiveEvent() { + final String VM_ID = "vmId"; + final int VM_PID = 2; + StubBundleContext bundleContext = new StubBundleContext(); + + VmStatusChangeNotifier notifier = new VmStatusChangeNotifier(bundleContext); + notifier.start(); + notifier.notifyVmStatusChange(Status.VM_STARTED, VM_ID, VM_PID); + + VmStatusListener listener = mock(VmStatusListener.class); + bundleContext.registerService(VmStatusListener.class, listener, null); + + verify(listener).vmStatusChanged(Status.VM_ACTIVE, VM_ID, VM_PID); + + } + + /* + * Some backends might activate on activation of another backend. If both of + * them are also VmStatusListener's, a concurrent modification exception + * might be thrown. This tests verifies it's OK to do so (concurrent modification). + */ + @Test + public void canAddListenersWhileFiringEvent() throws InterruptedException { + StubBundleContext bundleContext = new StubBundleContext(); + VmStatusChangeNotifier notifier = new VmStatusChangeNotifier(bundleContext); + + // Add > 2 listeners. One of them registers another listener in vmStatusChanged() + // Thus provoking ConcurrentModificationException. + bundleContext.registerService(VmStatusListener.class, new TestVmStatusListener(bundleContext), null); + bundleContext.registerService(VmStatusListener.class, new VmStatusListener() { + + @Override + public void vmStatusChanged(Status newStatus, String vmId, + int pid) { + Debug.println("Second registered listener fired"); + } + + @Override + public int hashCode() { + return 2; // second listener to be fired + } + + }, null); + bundleContext.registerService(VmStatusListener.class, new VmStatusListener() { + + @Override + public void vmStatusChanged(Status newStatus, String vmId, + int pid) { + Debug.println("Third registered listener fired"); + } + + @Override + public int hashCode() { + return 3; + } + + }, null); + notifier.start(); + + try { + notifier.notifyVmStatusChange(Status.VM_STARTED, "foo-vmid", 333); + // this will trigger the newly added listener being invoked and counting + // down the latch. + notifier.notifyVmStatusChange(Status.VM_STARTED, "foo-other", 9999); + // pass + } catch (ConcurrentModificationException e) { + fail("Unexpected conncurrent modification exception!"); + } + } + + static class TestVmStatusListener implements VmStatusListener { + + private final BundleContext context; + + private TestVmStatusListener(BundleContext context) { + this.context = context; + } + + @Override + public void vmStatusChanged(Status newStatus, String vmId, int pid) { + Debug.println("First registered listener fired"); + context.registerService(VmStatusListener.class, new VmStatusListener() { + + @Override + public void vmStatusChanged(Status newStatus, String vmId, + int pid) { + Debug.println("Listener registered in listener (between first and second) fired"); + } + + @Override + public int hashCode() { + // Pick a large hash code since that tends to result in + // the listener being fired later on. + return 101; + } + + }, null); + } + + @Override + public int hashCode() { + // Heuristic for HashMap it tends to be picked first when iterating over + return 1; + } + + } + + static class Debug { + + static final boolean debugOn = false; // set to true for debug output + + static void println(String msg) { + if (debugOn) { + System.err.println(msg); + } + } + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/model/InfoBuilderFactoryTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,53 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal.model; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class InfoBuilderFactoryTest { + + @Test + public void testCreateProcessEnvironmentBuilder() { + final InfoBuilderFactory builder = new InfoBuilderFactoryImpl(); + final ProcessEnvironmentBuilder hib = builder.createProcessEnvironmentBuilder(); + assertNotNull(hib); + assertTrue(hib instanceof ProcessEnvironmentBuilderImpl); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/model/VmInfoDAOTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,151 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal.model; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyListOf; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoDAOImpl.HttpHelper; +import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoDAOImpl.JsonHelper; +import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoDAOImpl.VmInfoUpdate; +import com.redhat.thermostat.jvm.overview.agent.model.VmInfo; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.util.StringContentProvider; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpStatus; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +public class VmInfoDAOTest { + + private static final String URL = "http://localhost:26000/api/v100/vm-info/systems/*/agents/foo-agent"; + private static final String UPDATE_URL = URL + "/jvms/vmId"; + private static final String SOME_JSON = "{\"some\" : \"json\"}"; + private static final String SOME_OTHER_JSON = "{\"some\" : {\"other\" : \"json\"}}"; + private static final String CONTENT_TYPE = "application/json"; + + private VmInfo info; + private JsonHelper jsonHelper; + private HttpHelper httpHelper; + private StringContentProvider contentProvider; + private Request request; + private ContentResponse response; + + @Before + public void setUp() throws Exception { + String vmId = "vmId"; + int vmPid = 1; + long startTime = 2L; + long stopTime = Long.MIN_VALUE; + String jVersion = "java 1.0"; + String jHome = "/path/to/jdk/home"; + String mainClass = "Hello.class"; + String commandLine = "World"; + String vmArgs = "-XX=+FastestJITPossible"; + String vmName = "Hotspot"; + String vmInfo = "Some info"; + String vmVersion = "1.0"; + Map<String, String> props = new HashMap<>(); + Map<String, String> env = new HashMap<>(); + String[] libs = new String[0]; + long uid = 2000L; + String username = "myUser"; + info = new VmInfo("foo-agent", vmId, vmPid, startTime, stopTime, jVersion, jHome, + mainClass, commandLine, vmName, vmInfo, vmVersion, vmArgs, + props, env, libs, uid, username); + + httpHelper = mock(HttpHelper.class); + contentProvider = mock(StringContentProvider.class); + when(httpHelper.createContentProvider(anyString())).thenReturn(contentProvider); + request = mock(Request.class); + when(httpHelper.newRequest(anyString())).thenReturn(request); + response = mock(ContentResponse.class); + when(response.getStatus()).thenReturn(HttpStatus.OK_200); + when(request.send()).thenReturn(response); + + jsonHelper = mock(JsonHelper.class); + when(jsonHelper.toJson(anyListOf(VmInfo.class))).thenReturn(SOME_JSON); + when(jsonHelper.toJson(any(VmInfoUpdate.class))).thenReturn(SOME_OTHER_JSON); + } + + @Test + public void testPutVmInfo() throws Exception { + VmInfoDAO dao = new VmInfoDAOImpl(httpHelper, jsonHelper); + dao.putVmInfo(info); + + verify(httpHelper).newRequest(URL); + verify(request).method(HttpMethod.POST); + verify(jsonHelper).toJson(eq(Arrays.asList(info))); + verify(httpHelper).createContentProvider(SOME_JSON); + verify(request).content(contentProvider, CONTENT_TYPE); + verify(request).send(); + verify(response).getStatus(); + } + + @Test + public void testPutVmStoppedTime() throws Exception { + VmInfoDAO dao = new VmInfoDAOImpl(httpHelper, jsonHelper); + dao.putVmStoppedTime("foo-agent", "vmId", 3L); + + verify(httpHelper).newRequest(UPDATE_URL); + verify(request).method(HttpMethod.PUT); + + ArgumentCaptor<VmInfoUpdate> updateCaptor = ArgumentCaptor.forClass(VmInfoUpdate.class); + verify(jsonHelper).toJson(updateCaptor.capture()); + VmInfoUpdate update = updateCaptor.getValue(); + assertEquals(3L, update.getStoppedTime()); + + verify(httpHelper).createContentProvider(SOME_OTHER_JSON); + verify(request).content(contentProvider, CONTENT_TYPE); + verify(request).send(); + verify(response).getStatus(); + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/agent/src/test/java/com/redhat/thermostat/jvm/overview/agent/internal/model/VmInfoTypeAdapterTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,106 @@ +/* + * 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 + * <http://www.gnu.org/licenses/>. + * + * 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.jvm.overview.agent.internal.model; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoDAOImpl.VmInfoUpdate; +import com.redhat.thermostat.jvm.overview.agent.internal.model.VmInfoTypeAdapter.VmInfoUpdateTypeAdapter; +import com.redhat.thermostat.jvm.overview.agent.model.VmInfo; +import org.junit.Test; + +public class VmInfoTypeAdapterTest { + + @Test + public void testWrite() throws Exception { + VmInfoTypeAdapter adapter = new VmInfoTypeAdapter(); + final String expected = "[{\"agentId\":\"agent1\",\"vmId\":\"vm1\",\"vmPid\":8000," + + "\"startTimeStamp\":{\"$numberLong\":\"50000\"},\"stopTimeStamp\":" + + "{\"$numberLong\":\"-9223372036854775808\"},\"javaVersion\":\"1.8.0\"," + + "\"javaHome\":\"/path/to/java\",\"mainClass\":\"myClass\",\"javaCommandLine\":\"java myClass\"," + + "\"vmName\":\"myJVM\",\"vmArguments\":\"-Dhello\",\"vmInfo\":\"interesting\"," + + "\"vmVersion\":\"1800\",\"propertiesAsArray\":[{\"key\":\"A\",\"value\":\"B\"}," + + "{\"key\":\"C\",\"value\":\"D\"}],\"environmentAsArray\":[{\"key\":\"E\",\"value\":\"F\"}," + + "{\"key\":\"G\",\"value\":\"H\"}],\"loadedNativeLibraries\":[],\"uid\":{\"$numberLong\":\"1234\"}," + + "\"username\":\"test\"}," + + "{\"agentId\":\"agent2\",\"vmId\":\"vm2\",\"vmPid\":9000,\"startTimeStamp\":" + + "{\"$numberLong\":\"100000\"},\"stopTimeStamp\":{\"$numberLong\":\"200000\"}," + + "\"javaVersion\":\"1.7.0\",\"javaHome\":\"/path/to/jre\",\"mainClass\":\"myOtherClass\"," + + "\"javaCommandLine\":\"otherClass.sh\",\"vmName\":\"myOtherJVM\",\"vmArguments\":\"-Dworld\"," + + "\"vmInfo\":\"info\",\"vmVersion\":\"1700\",\"propertiesAsArray\":[],\"environmentAsArray\":" + + "[{\"key\":\"A\",\"value\":\"B\"},{\"key\":\"C\",\"value\":\"D\"}]," + + "\"loadedNativeLibraries\":[\"libhello\",\"libworld\"],\"uid\":{\"$numberLong\":\"5678\"}" + + ",\"username\":\"user\"}]"; + + final Map<String, String> props = new HashMap<>(); + props.put("A", "B"); + props.put("C", "D"); + final Map<String, String> env = new HashMap<>(); + env.put("E", "F"); + env.put("G", "H"); + VmInfo first = new VmInfo("agent1", "vm1", 8000, 50000L, Long.MIN_VALUE, "1.8.0", "/path/to/java", "myClass", + "java myClass", "myJVM", "interesting", "1800", "-Dhello", props, env, new String[0], 1234L, "test"); + + final Map<String, String> props2 = new HashMap<>(); + final Map<String, String> env2 = new HashMap<>(); + env2.put("A", "B"); + env2.put("C", "D"); + final String[] libs = { "libhello", "libworld" }; + VmInfo second = new VmInfo("agent2", "vm2", 9000, 100000L, 200000L, "1.7.0", "/path/to/jre", "myOtherClass", + "otherClass.sh", "myOtherJVM", "info", "1700", "-Dworld", props2, env2, libs, 5678L, "user"); + List<VmInfo> infos = Arrays.asList(first, second); + + String json = adapter.toJson(infos); + assertEquals(expected, json); + } + + @Test + public void testUpdate() throws Exception { + VmInfoUpdateTypeAdapter adapter = new VmInfoUpdateTypeAdapter(); + final String expected = "{\"set\":{\"stopTimeStamp\":{\"$numberLong\":\"5000\"}}}"; + + VmInfoUpdate update = new VmInfoUpdate(5000L); + String json = adapter.toJson(update); + assertEquals(expected, json); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/distribution/assemblies/plugin-assembly.xml Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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 + <http://www.gnu.org/licenses/>. + + 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. + +--> +<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd"> + <id>plugin-assembly</id> + <formats> + <format>zip</format> + </formats> + <includeBaseDirectory>false</includeBaseDirectory> + + <dependencySets> + <dependencySet> + <includes> + <include>com.redhat.thermostat:thermostat-jvm-overview-agent</include> + </includes> + <useProjectArtifact>false</useProjectArtifact> + <useStrictFiltering>true</useStrictFiltering> + <outputDirectory>plugins/${thermostat.plugin}</outputDirectory> + </dependencySet> + </dependencySets> + + <fileSets> + <fileSet> + <includes> + <include>thermostat-plugin.xml</include> + </includes> + <outputDirectory>plugins/${thermostat.plugin}</outputDirectory> + <filtered>true</filtered> + </fileSet> + </fileSets> +</assembly> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/distribution/pom.xml Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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 + <http://www.gnu.org/licenses/>. + + 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. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-jvm-overview</artifactId> + <version>1.99.12-SNAPSHOT</version> + </parent> + + <artifactId>thermostat-jvm-overview-distribution</artifactId> + <packaging>pom</packaging> + + <name>Thermostat JVM Overview plugin distribution</name> + + <properties> + <thermostat.plugin>jvm-overview</thermostat.plugin> + </properties> + + <build> + <plugins> + <plugin> + <artifactId>maven-assembly-plugin</artifactId> + <configuration> + <descriptors> + <descriptor>assemblies/plugin-assembly.xml</descriptor> + </descriptors> + <appendAssemblyId>false</appendAssemblyId> + </configuration> + <executions> + <execution> + <id>assemble-plugin</id> + <phase>package</phase> + <goals> + <goal>single</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-jvm-overview-agent</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + +</project> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/distribution/thermostat-plugin.xml Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,51 @@ +<?xml version="1.0"?> +<!-- + + 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 + <http://www.gnu.org/licenses/>. + + 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. + +--> +<plugin xmlns="http://icedtea.classpath.org/thermostat/plugins/v1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://icedtea.classpath.org/thermostat/plugins/v1.0 thermostat-plugin.xsd"> + <extensions> + <extension> + <name>agent</name> + <bundles> + <bundle><symbolic-name>com.redhat.thermostat.jvm.overview</symbolic-name><version>${project.version}</version></bundle> + </bundles> + </extension> + </extensions> +</plugin> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/jvm-overview/pom.xml Fri Jun 09 16:38:44 2017 +0200 @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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 + <http://www.gnu.org/licenses/>. + + 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. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-plugins</artifactId> + <version>1.99.12-SNAPSHOT</version> + </parent> + + <artifactId>thermostat-jvm-overview</artifactId> + <packaging>pom</packaging> + + <name>Thermostat JVM Overview plugin</name> + + <modules> + <module>agent</module> + <module>distribution</module> + </modules> + +</project> +
--- a/plugins/pom.xml Thu Jun 08 20:16:03 2017 +0200 +++ b/plugins/pom.xml Fri Jun 09 16:38:44 2017 +0200 @@ -54,14 +54,15 @@ <!--<module>thread</module>--> <module>killvm</module> <module>host-overview</module> + <module>jvm-overview</module> + <module>vm-gc</module> + <module>vm-memory</module> <!--<module>host-cpu</module>--> <!--<module>host-memory</module>--> <!--<module>vm-byteman</module>--> <!--<module>vm-cpu</module>--> - <module>vm-gc</module> <!--<module>vm-classstat</module>--> <!--<module>vm-compiler</module>--> - <module>vm-memory</module> <!--<module>vm-heap-analysis</module>--> <!--<module>vm-io</module>--> <!--<module>vm-jmx</module>-->
--- a/plugins/vm-gc/agent/pom.xml Thu Jun 08 20:16:03 2017 +0200 +++ b/plugins/vm-gc/agent/pom.xml Fri Jun 09 16:38:44 2017 +0200 @@ -122,6 +122,11 @@ </dependency> <dependency> <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-jvm-overview-agent</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> <artifactId>thermostat-common-test</artifactId> <version>${project.version}</version> <scope>test</scope>
--- a/plugins/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackend.java Thu Jun 08 20:16:03 2017 +0200 +++ b/plugins/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackend.java Fri Jun 09 16:38:44 2017 +0200 @@ -36,17 +36,16 @@ package com.redhat.thermostat.vm.gc.agent.internal; +import com.redhat.thermostat.jvm.overview.agent.VmListenerBackend; +import com.redhat.thermostat.jvm.overview.agent.VmStatusListenerRegistrar; +import com.redhat.thermostat.jvm.overview.agent.VmUpdateListener; 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 com.redhat.thermostat.agent.VmStatusListenerRegistrar; import com.redhat.thermostat.backend.Backend; -import com.redhat.thermostat.backend.VmListenerBackend; -import com.redhat.thermostat.backend.VmUpdateListener; import com.redhat.thermostat.common.Version; import com.redhat.thermostat.storage.core.WriterID; import com.redhat.thermostat.vm.gc.common.Constants;
--- a/plugins/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcDataExtractor.java Thu Jun 08 20:16:03 2017 +0200 +++ b/plugins/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcDataExtractor.java Fri Jun 09 16:38:44 2017 +0200 @@ -36,8 +36,8 @@ package com.redhat.thermostat.vm.gc.agent.internal; -import com.redhat.thermostat.backend.VmUpdate; -import com.redhat.thermostat.backend.VmUpdateException; +import com.redhat.thermostat.jvm.overview.agent.VmUpdate; +import com.redhat.thermostat.jvm.overview.agent.VmUpdateException; /** * A helper class to provide type-safe access to commonly used jvmstat monitors
--- a/plugins/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcVmListener.java Thu Jun 08 20:16:03 2017 +0200 +++ b/plugins/vm-gc/agent/src/main/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcVmListener.java Fri Jun 09 16:38:44 2017 +0200 @@ -39,10 +39,10 @@ import java.util.logging.Level; import java.util.logging.Logger; -import com.redhat.thermostat.backend.VmUpdate; -import com.redhat.thermostat.backend.VmUpdateException; -import com.redhat.thermostat.backend.VmUpdateListener; import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.jvm.overview.agent.VmUpdate; +import com.redhat.thermostat.jvm.overview.agent.VmUpdateException; +import com.redhat.thermostat.jvm.overview.agent.VmUpdateListener; import com.redhat.thermostat.vm.gc.common.VmGcStatDAO; import com.redhat.thermostat.vm.gc.common.model.VmGcStat;
--- a/plugins/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackendTest.java Thu Jun 08 20:16:03 2017 +0200 +++ b/plugins/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcBackendTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -44,13 +44,13 @@ import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; +import com.redhat.thermostat.jvm.overview.agent.VmStatusListenerRegistrar; import org.junit.Before; import org.junit.Test; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.Version; -import com.redhat.thermostat.agent.VmStatusListenerRegistrar; import com.redhat.thermostat.common.Ordered; import com.redhat.thermostat.storage.core.WriterID; import com.redhat.thermostat.vm.gc.agent.internal.VmGcBackend.ListenerCreator;
--- a/plugins/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcDataExtractorTest.java Thu Jun 08 20:16:03 2017 +0200 +++ b/plugins/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcDataExtractorTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -41,12 +41,11 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.redhat.thermostat.jvm.overview.agent.VmUpdate; +import com.redhat.thermostat.jvm.overview.agent.VmUpdateException; import org.junit.Before; import org.junit.Test; -import com.redhat.thermostat.backend.VmUpdate; -import com.redhat.thermostat.backend.VmUpdateException; - public class VmGcDataExtractorTest { private VmGcDataExtractor extractor;
--- a/plugins/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcVmListenerTest.java Thu Jun 08 20:16:03 2017 +0200 +++ b/plugins/vm-gc/agent/src/test/java/com/redhat/thermostat/vm/gc/agent/internal/VmGcVmListenerTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -47,11 +47,11 @@ import java.util.List; import java.util.concurrent.TimeUnit; +import com.redhat.thermostat.jvm.overview.agent.VmUpdateException; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; -import com.redhat.thermostat.backend.VmUpdateException; import com.redhat.thermostat.vm.gc.common.VmGcStatDAO; import com.redhat.thermostat.vm.gc.common.model.VmGcStat;
--- a/plugins/vm-memory/agent/pom.xml Thu Jun 08 20:16:03 2017 +0200 +++ b/plugins/vm-memory/agent/pom.xml Fri Jun 09 16:38:44 2017 +0200 @@ -111,6 +111,11 @@ </dependency> <dependency> <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-jvm-overview-agent</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> <artifactId>thermostat-common-test</artifactId> <version>${project.version}</version> <scope>test</scope>
--- a/plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/Activator.java Thu Jun 08 20:16:03 2017 +0200 +++ b/plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/Activator.java Fri Jun 09 16:38:44 2017 +0200 @@ -36,14 +36,14 @@ package com.redhat.thermostat.vm.memory.agent.internal; +import com.redhat.thermostat.jvm.overview.agent.VmListenerBackend; +import com.redhat.thermostat.jvm.overview.agent.VmStatusListenerRegistrar; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; -import com.redhat.thermostat.agent.VmStatusListenerRegistrar; import com.redhat.thermostat.backend.Backend; import com.redhat.thermostat.backend.BackendService; -import com.redhat.thermostat.backend.VmListenerBackend; import com.redhat.thermostat.common.MultipleServiceTracker; import com.redhat.thermostat.common.MultipleServiceTracker.Action; import com.redhat.thermostat.common.MultipleServiceTracker.DependencyProvider;
--- a/plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackend.java Thu Jun 08 20:16:03 2017 +0200 +++ b/plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackend.java Fri Jun 09 16:38:44 2017 +0200 @@ -36,10 +36,10 @@ package com.redhat.thermostat.vm.memory.agent.internal; -import com.redhat.thermostat.agent.VmStatusListenerRegistrar; -import com.redhat.thermostat.backend.VmListenerBackend; -import com.redhat.thermostat.backend.VmUpdateListener; import com.redhat.thermostat.common.Version; +import com.redhat.thermostat.jvm.overview.agent.VmListenerBackend; +import com.redhat.thermostat.jvm.overview.agent.VmStatusListenerRegistrar; +import com.redhat.thermostat.jvm.overview.agent.VmUpdateListener; import com.redhat.thermostat.storage.core.WriterID; import com.redhat.thermostat.vm.memory.common.Constants; import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO; @@ -50,9 +50,11 @@ private final VmMemoryStatDAO vmMemoryStats; private final VmTlabStatDAO tlabStats; - public VmMemoryBackend(VmMemoryStatDAO vmMemoryStatDAO, VmTlabStatDAO vmTlabStatDAO, - Version version, - VmStatusListenerRegistrar registrar, WriterID writerId) { + public VmMemoryBackend(VmMemoryStatDAO vmMemoryStatDAO, + VmTlabStatDAO vmTlabStatDAO, + Version version, + VmStatusListenerRegistrar registrar, + WriterID writerId) { super("VM Memory Backend", "Gathers memory statistics about a JVM", "Red Hat, Inc.",
--- a/plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryDataExtractor.java Thu Jun 08 20:16:03 2017 +0200 +++ b/plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryDataExtractor.java Fri Jun 09 16:38:44 2017 +0200 @@ -36,8 +36,8 @@ package com.redhat.thermostat.vm.memory.agent.internal; -import com.redhat.thermostat.backend.VmUpdate; -import com.redhat.thermostat.backend.VmUpdateException; +import com.redhat.thermostat.jvm.overview.agent.VmUpdate; +import com.redhat.thermostat.jvm.overview.agent.VmUpdateException; import com.redhat.thermostat.vm.memory.common.model.VmMemoryStat.Generation; /**
--- a/plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryVmListener.java Thu Jun 08 20:16:03 2017 +0200 +++ b/plugins/vm-memory/agent/src/main/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryVmListener.java Fri Jun 09 16:38:44 2017 +0200 @@ -41,12 +41,12 @@ import java.util.logging.Level; import java.util.logging.Logger; -import com.redhat.thermostat.backend.VmUpdate; -import com.redhat.thermostat.backend.VmUpdateException; -import com.redhat.thermostat.backend.VmUpdateListener; import com.redhat.thermostat.common.Clock; import com.redhat.thermostat.common.SystemClock; import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.jvm.overview.agent.VmUpdate; +import com.redhat.thermostat.jvm.overview.agent.VmUpdateException; +import com.redhat.thermostat.jvm.overview.agent.VmUpdateListener; import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO; import com.redhat.thermostat.vm.memory.common.VmTlabStatDAO; import com.redhat.thermostat.vm.memory.common.model.VmMemoryStat;
--- a/plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/ActivatorTest.java Thu Jun 08 20:16:03 2017 +0200 +++ b/plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/ActivatorTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -43,13 +43,13 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.redhat.thermostat.jvm.overview.agent.VmListenerBackend; import org.junit.Test; import org.osgi.framework.Bundle; import org.osgi.framework.Version; import com.redhat.thermostat.backend.Backend; import com.redhat.thermostat.backend.BackendService; -import com.redhat.thermostat.backend.VmListenerBackend; import com.redhat.thermostat.storage.core.WriterID; import com.redhat.thermostat.testutils.StubBundleContext; import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO;
--- a/plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackendTest.java Thu Jun 08 20:16:03 2017 +0200 +++ b/plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryBackendTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -40,10 +40,10 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.redhat.thermostat.jvm.overview.agent.VmStatusListenerRegistrar; import org.junit.Before; import org.junit.Test; -import com.redhat.thermostat.agent.VmStatusListenerRegistrar; import com.redhat.thermostat.common.Ordered; import com.redhat.thermostat.common.Version; import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO;
--- a/plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryDataExtractorTest.java Thu Jun 08 20:16:03 2017 +0200 +++ b/plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryDataExtractorTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -41,11 +41,11 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.redhat.thermostat.jvm.overview.agent.VmUpdate; +import com.redhat.thermostat.jvm.overview.agent.VmUpdateException; import org.junit.Before; import org.junit.Test; -import com.redhat.thermostat.backend.VmUpdate; -import com.redhat.thermostat.backend.VmUpdateException; import com.redhat.thermostat.vm.memory.common.model.VmMemoryStat.Generation; public class VmMemoryDataExtractorTest {
--- a/plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryVmListenerTest.java Thu Jun 08 20:16:03 2017 +0200 +++ b/plugins/vm-memory/agent/src/test/java/com/redhat/thermostat/vm/memory/agent/internal/VmMemoryVmListenerTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -46,12 +46,12 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import com.redhat.thermostat.jvm.overview.agent.VmUpdate; +import com.redhat.thermostat.jvm.overview.agent.VmUpdateException; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; -import com.redhat.thermostat.backend.VmUpdate; -import com.redhat.thermostat.backend.VmUpdateException; import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO; import com.redhat.thermostat.vm.memory.common.VmTlabStatDAO; import com.redhat.thermostat.vm.memory.common.model.VmMemoryStat;
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/HostsVMsLoader.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.storage.core; - -import java.util.Collection; - - -/** - * Provides a way to load the current hosts and VMs. - */ -public interface HostsVMsLoader { - - Collection<HostRef> getHosts(); - Collection<VmRef> getVMs(HostRef host); -} -
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmBoundaryPojoGetter.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,120 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.storage.core; - -import java.util.logging.Logger; - -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.storage.model.TimeStampedPojo; - -public class VmBoundaryPojoGetter<T extends TimeStampedPojo> { - - // QUERY %s WHERE 'agentId' = ?s AND \ - // 'vmId' = ?s \ - // SORT 'timeStamp' DSC \ - // LIMIT 1 - public static final String DESC_NEWEST_VM_STAT = "QUERY %s " + - "WHERE '" + Key.AGENT_ID.getName() + "' = ?s " + - "AND '" + Key.VM_ID.getName() + "' = ?s " + - "SORT '" + Key.TIMESTAMP.getName() + "' DSC " + - "LIMIT 1"; - - // QUERY %s WHERE 'agentId' = ?s AND \ - // 'vmId' = ?s \ - // SORT 'timeStamp' ASC \ - // LIMIT 1 - public static final String DESC_OLDEST_VM_STAT = "QUERY %s " + - "WHERE '" + Key.AGENT_ID.getName() + "' = ?s " + - "AND '" + Key.VM_ID.getName() + "' = ?s " + - "SORT '" + Key.TIMESTAMP.getName() + "' ASC " + - "LIMIT 1"; - - private static final Logger logger = LoggingUtils.getLogger(VmBoundaryPojoGetter.class); - - private final Category<T> cat; - private final String queryNewest; - private final String queryOldest; - - public VmBoundaryPojoGetter(Category<T> cat) { - this.cat = cat; - this.queryNewest = String.format(DESC_NEWEST_VM_STAT, cat.getName()); - this.queryOldest = String.format(DESC_OLDEST_VM_STAT, cat.getName()); - } - - /** - * @deprecated use {@link #getNewestStat(VmId, AgentId)} - */ - @Deprecated - public T getNewestStat(VmRef ref) { - return runAgentAndVmIdQuery(ref.getVmId(), ref.getHostRef().getAgentId(), queryNewest); - } - - public T getNewestStat(VmId vmId, AgentId agentId) { - return runAgentAndVmIdQuery(vmId.get(), agentId.get(), queryNewest); - } - - /** - * @deprecated use {@link #getOldestStat(VmId, AgentId)} - */ - @Deprecated - public T getOldestStat(VmRef ref) { - return runAgentAndVmIdQuery(ref.getVmId(), ref.getHostRef().getAgentId(), queryOldest); - } - - public T getOldestStat(VmId vmId, AgentId agentId) { - return runAgentAndVmIdQuery(vmId.get(), agentId.get(), queryOldest); - } - - private T runAgentAndVmIdQuery(final String vmId, final String agentId, final String descriptor) { - return null; - } - - //Package private for testing - String getNewestQueryDesc() { - return queryNewest; - } - - //Package private for testing - String getOldestQueryDesc() { - return queryOldest; - } - - protected Logger getLogger() { - return logger; - } - -}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmId.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.storage.core; - -/** - * This class uniquely identifies a Java Virtual Machine - * - */ -public class VmId extends Id { - - public VmId(String id) { - super(id); - } -}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmLatestPojoListGetter.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.storage.core; - -import java.util.List; -import java.util.logging.Logger; - -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.storage.model.TimeStampedPojo; - -/** - * Get a {@link List} of {@link TimeStampedPojo}s newer than a given time stamp. - * - * @see VmTimeIntervalPojoListGetter - */ -public class VmLatestPojoListGetter<T extends TimeStampedPojo> { - - public static final String VM_LATEST_QUERY_FORMAT = "QUERY %s WHERE '" - + Key.AGENT_ID.getName() + "' = ?s AND '" - + Key.VM_ID.getName() + "' = ?s AND '" - + Key.TIMESTAMP.getName() + "' > ?l SORT '" - + Key.TIMESTAMP.getName() + "' DSC"; - private static final Logger logger = LoggingUtils.getLogger(VmLatestPojoListGetter.class); - - private final Category<T> cat; - private final String queryLatest; - - public VmLatestPojoListGetter(Category<T> cat) { - this.cat = cat; - this.queryLatest = String.format(VM_LATEST_QUERY_FORMAT, cat.getName()); - } - - /** - * @deprecated use {@link #getLatest(AgentId, VmId, long)} - */ - @Deprecated - public List<T> getLatest(VmRef vmRef, long since) { - return getLatest(new AgentId(vmRef.getHostRef().getAgentId()), new VmId(vmRef.getVmId()), since); - } - - public List<T> getLatest(final AgentId agentId, final VmId vmId, final long since) { - return null; - } - - // package private for tests - String getQueryLatestDesc() { - return queryLatest; - } - - public Logger getLogger() { - return logger; - } - -} -
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmRef.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.storage.core; - -import com.redhat.thermostat.storage.model.VmInfo; - -public class VmRef implements Ref { - - private final HostRef hostRef; - private final String id; - private final Integer pid; - private final String name; - - public VmRef(HostRef hostRef, String id, Integer pid, String name) { - this.hostRef = hostRef; - this.id = id; - this.pid = pid; - this.name = name; - } - - public VmRef(HostRef hostRef, VmInfo vmInfo) { - this.hostRef = hostRef; - this.id = vmInfo.getVmId(); - this.pid = vmInfo.getVmPid(); - this.name = vmInfo.getMainClass(); - } - - @Override - public String toString() { - return name; - } - - public HostRef getHostRef() { - return hostRef; - } - - public String getVmId() { - return id; - } - - public Integer getPid() { - return pid; - } - - public String getName() { - return name; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (obj == this) { - return true; - } - if (obj.getClass() != this.getClass()) { - return false; - } - VmRef other = (VmRef) obj; - if (equals(this.hostRef, other.hostRef) - && equals(this.id, other.id) - && equals(this.pid, other.pid) && equals(this.name, other.name)) { - return true; - } - return false; - } - - private static boolean equals(Object obj1, Object obj2) { - return (obj1 == null && obj2 == null) || (obj1 != null && obj1.equals(obj2)); - } - - @Override - public int hashCode() { - return id.hashCode(); - } - - @Override - public String getStringID() { - return id; - } -} -
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/VmTimeIntervalPojoListGetter.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.storage.core; - -import java.util.List; -import java.util.logging.Logger; - -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.storage.model.TimeStampedPojo; - -/** - * Get a {@link List} of {@link TimeStampedPojo}s in a given time interval - * range. - * - * @see VmLatestPojoListGetter - */ -public class VmTimeIntervalPojoListGetter<T extends TimeStampedPojo> { - - // The query for VmTimeIntervalPojoListGetter should query for since <= timestamp < to - // in order not to miss data for multiple consecutive queries of the form [a, b), [b, c), ... - // If the query were since < timestamp < to then queries of (a, b), (b, c), ... would - // result in missed data at the endpoints (b, ...) - public static final String VM_INTERVAL_QUERY_FORMAT = "QUERY %s WHERE '" - + Key.AGENT_ID.getName() + "' = ?s AND '" - + Key.VM_ID.getName() + "' = ?s AND '" - + Key.TIMESTAMP.getName() + "' >= ?l AND '" - + Key.TIMESTAMP.getName() + "' < ?l SORT '" - + Key.TIMESTAMP.getName() + "' DSC"; - - private static final Logger logger = LoggingUtils.getLogger(VmTimeIntervalPojoListGetter.class); - - private final Category<T> cat; - private final String query; - - public VmTimeIntervalPojoListGetter(Category<T> cat) { - this.cat = cat; - this.query = String.format(VM_INTERVAL_QUERY_FORMAT, cat.getName()); - } - - /** - * @deprecated use {@link #getLatest(AgentId, VmId, long, long)} - */ - @Deprecated - public List<T> getLatest(final VmRef vmRef, final long since, final long to) { - return getLatest(new AgentId(vmRef.getHostRef().getAgentId()), new VmId(vmRef.getVmId()), since, to); - } - - public List<T> getLatest(final AgentId agentId, final VmId vmId, final long since, final long to) { - return null; - } - - // package private for tests - String getQueryLatestDesc() { - return query; - } - - protected Logger getLogger() { - return logger; - } -}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/VmInfoDAO.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.storage.dao; - -import java.util.Set; - -import com.redhat.thermostat.annotations.Service; -import com.redhat.thermostat.storage.core.AgentId; -import com.redhat.thermostat.storage.core.VmId; -import com.redhat.thermostat.storage.model.VmInfo; - -@Service -public interface VmInfoDAO { - - /** @return {@code null} if no information can be found */ - VmInfo getVmInfo(VmId id); - - /** - * - * @param agentId The id of host to get the VM(s) for. - * @return A set of the VmId(s). - */ - Set<VmId> getVmIds(AgentId agentId); - - void putVmInfo(VmInfo info); - - void putVmStoppedTime(String agentId, String vmId, long since); -} -
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/Activator.java Thu Jun 08 20:16:03 2017 +0200 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/Activator.java Fri Jun 09 16:38:44 2017 +0200 @@ -48,11 +48,9 @@ import com.redhat.thermostat.storage.dao.AgentInfoDAO; import com.redhat.thermostat.storage.dao.BackendInfoDAO; import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO; -import com.redhat.thermostat.storage.dao.VmInfoDAO; import com.redhat.thermostat.storage.internal.dao.AgentInfoDAOImpl; import com.redhat.thermostat.storage.internal.dao.BackendInfoDAOImpl; import com.redhat.thermostat.storage.internal.dao.NetworkInterfaceInfoDAOImpl; -import com.redhat.thermostat.storage.internal.dao.VmInfoDAOImpl; public class Activator implements BundleActivator { @@ -84,10 +82,6 @@ NetworkInterfaceInfoDAO networkInfoDao = new NetworkInterfaceInfoDAOImpl(); reg = context.registerService(NetworkInterfaceInfoDAO.class.getName(), networkInfoDao, null); regs.add(reg); - - VmInfoDAO vmInfoDao = new VmInfoDAOImpl(); - reg = context.registerService(VmInfoDAO.class.getName(), vmInfoDao, null); - regs.add(reg); } private void unregisterServices() {
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOImpl.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,249 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.storage.internal.dao; - -import java.io.IOException; -import java.net.URI; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.HttpContentResponse; -import org.eclipse.jetty.client.HttpRequest; -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.client.api.Request; -import org.eclipse.jetty.client.util.StringContentProvider; -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.HttpStatus; - -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.storage.core.AgentId; -import com.redhat.thermostat.storage.core.VmId; -import com.redhat.thermostat.storage.dao.VmInfoDAO; -import com.redhat.thermostat.storage.internal.dao.VmInfoTypeAdapter.VmInfoUpdateTypeAdapter; -import com.redhat.thermostat.storage.model.VmInfo; - -public class VmInfoDAOImpl implements VmInfoDAO { - - private final Logger logger = LoggingUtils.getLogger(VmInfoDAOImpl.class); - - private static final String GATEWAY_URL = "http://localhost:26000/api/v100"; // TODO configurable - private static final String GATEWAY_PATH = "/vm-info/systems/*/agents/"; - private static final String GATEWAY_PATH_JVM_SUFFIX = "/jvms/"; - private static final String CONTENT_TYPE = "application/json"; - - private final HttpHelper httpHelper; - private final JsonHelper jsonHelper; - - public VmInfoDAOImpl() throws Exception { - this(new HttpHelper(new HttpClient()), new JsonHelper(new VmInfoTypeAdapter(), new VmInfoUpdateTypeAdapter())); - } - - VmInfoDAOImpl(HttpHelper httpHelper, JsonHelper jsonHelper) throws Exception { - this.jsonHelper = jsonHelper; - this.httpHelper = httpHelper; - - this.httpHelper.startClient(); - } - - @Override - public VmInfo getVmInfo(final VmId id) { - return null; // TODO Remove once VM Id completer is removed - } - - @Override - public Set<VmId> getVmIds(AgentId agentId) { - return Collections.emptySet(); // TODO Remove once VM Id completer is removed - } - - @Override - public void putVmInfo(final VmInfo info) { - try { - // Encode as JSON and send as POST request - String json = jsonHelper.toJson(Arrays.asList(info)); - StringContentProvider provider = httpHelper.createContentProvider(json); - - String url = getAddURL(info.getAgentId()); - Request httpRequest = httpHelper.newRequest(url); - httpRequest.method(HttpMethod.POST); - httpRequest.content(provider, CONTENT_TYPE); - sendRequest(httpRequest); - } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) { - logger.log(Level.WARNING, "Failed to send JVM information to web gateway", e); - } - } - - @Override - public void putVmStoppedTime(final String agentId, final String vmId, final long timestamp) { - try { - // Encode as JSON and send as PUT request - VmInfoUpdate update = new VmInfoUpdate(timestamp); - String json = jsonHelper.toJson(update); - StringContentProvider provider = httpHelper.createContentProvider(json); - - String url = getUpdateURL(agentId, vmId); - Request httpRequest = httpHelper.newRequest(url); - httpRequest.method(HttpMethod.PUT); - httpRequest.content(provider, CONTENT_TYPE); - sendRequest(httpRequest); - } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) { - logger.log(Level.WARNING, "Failed to send JVM information update to web gateway", e); - } - } - - private void sendRequest(Request httpRequest) - throws InterruptedException, TimeoutException, ExecutionException, IOException { - ContentResponse resp = httpRequest.send(); - int status = resp.getStatus(); - if (status != HttpStatus.OK_200) { - throw new IOException("Gateway returned HTTP status " + String.valueOf(status) + " - " + resp.getReason()); - } - } - - private String getAddURL(String agentId) { - StringBuilder builder = buildURL(agentId); - return builder.toString(); - } - - private StringBuilder buildURL(String agentId) { - StringBuilder builder = new StringBuilder(); - builder.append(GATEWAY_URL); - builder.append(GATEWAY_PATH); - builder.append(agentId); - return builder; - } - - private String getUpdateURL(String agentId, String vmId) { - StringBuilder builder = buildURL(agentId); - builder.append(GATEWAY_PATH_JVM_SUFFIX); - builder.append(vmId); - return builder.toString(); - } - - static class VmInfoUpdate { - - private final long stoppedTime; - - VmInfoUpdate(long stoppedTime) { - this.stoppedTime = stoppedTime; - } - - long getStoppedTime() { - return stoppedTime; - } - } - - - // For testing purposes - static class JsonHelper { - - private final VmInfoTypeAdapter typeAdapter; - private final VmInfoUpdateTypeAdapter updateTypeAdapter; - - public JsonHelper(VmInfoTypeAdapter typeAdapter, VmInfoUpdateTypeAdapter updateTypeAdapter) { - this.typeAdapter = typeAdapter; - this.updateTypeAdapter = updateTypeAdapter; - } - - String toJson(List<VmInfo> infos) throws IOException { - return typeAdapter.toJson(infos); - } - - String toJson(VmInfoUpdate update) throws IOException { - return updateTypeAdapter.toJson(update); - } - - } - - // For testing purposes - static class HttpHelper { - - private final HttpClient httpClient; - - HttpHelper(HttpClient httpClient) { - this.httpClient = httpClient; - } - - void startClient() throws Exception { - httpClient.start(); - } - - StringContentProvider createContentProvider(String content) { - return new StringContentProvider(content); - } - - Request newRequest(String url) { - return new MockRequest(httpClient, URI.create(url)); - } - - } - - // FIXME This class should be removed when the web gateway has a microservice for this DAO - private static class MockRequest extends HttpRequest { - - MockRequest(HttpClient client, URI uri) { - super(client, uri); - } - - @Override - public ContentResponse send() throws InterruptedException, TimeoutException, ExecutionException { - return new MockResponse(); - } - - } - - // FIXME This class should be removed when the web gateway has a microservice for this DAO - private static class MockResponse extends HttpContentResponse { - - MockResponse() { - super(null, null, null); - } - - @Override - public int getStatus() { - return HttpStatus.OK_200; - } - - } -} -
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/VmInfoTypeAdapter.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,198 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.storage.internal.dao; - -import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import com.redhat.thermostat.storage.internal.dao.VmInfoDAOImpl.VmInfoUpdate; -import com.redhat.thermostat.storage.model.VmInfo; - -public class VmInfoTypeAdapter extends TypeAdapter<List<VmInfo>> { - - private static final String AGENT_ID = "agentId"; - private static final String VM_ID = "vmId"; - private static final String VM_PID = "vmPid"; - private static final String JAVA_VERSION = "javaVersion"; - private static final String JAVA_HOME = "javaHome"; - private static final String MAIN_CLASS = "mainClass"; - private static final String JAVA_COMMAND_LINE = "javaCommandLine"; - private static final String VM_ARGUMENTS = "vmArguments"; - private static final String VM_NAME = "vmName"; - private static final String VM_INFO = "vmInfo"; - private static final String VM_VERSION = "vmVersion"; - private static final String PROPERTIES_AS_ARRAY = "propertiesAsArray"; - private static final String ENVIRONMENT_AS_ARRAY = "environmentAsArray"; - private static final String LOADED_NATIVE_LIBRARIES = "loadedNativeLibraries"; - private static final String START_TIME_STAMP = "startTimeStamp"; - private static final String STOP_TIME_STAMP = "stopTimeStamp"; - private static final String UID = "uid"; - private static final String USERNAME = "username"; - private static final String TYPE_LONG = "$numberLong"; - private static final String KEY = "key"; - private static final String VALUE = "value"; - - @Override - public void write(JsonWriter out, List<VmInfo> value) throws IOException { - // Request is an array of VmInfo objects - out.beginArray(); - - for (VmInfo info : value) { - writeVmInfo(out, info); - } - - out.endArray(); - } - - private void writeVmInfo(JsonWriter out, VmInfo info) throws IOException { - out.beginObject(); - - // Write each field of VmInfo as part of a JSON object - out.name(AGENT_ID); - out.value(info.getAgentId()); - out.name(VM_ID); - out.value(info.getVmId()); - out.name(VM_PID); - out.value(info.getVmPid()); - out.name(START_TIME_STAMP); - writeLong(out, info.getStartTimeStamp()); - out.name(STOP_TIME_STAMP); - writeLong(out, info.getStopTimeStamp()); - out.name(JAVA_VERSION); - out.value(info.getJavaVersion()); - out.name(JAVA_HOME); - out.value(info.getJavaHome()); - out.name(MAIN_CLASS); - out.value(info.getMainClass()); - out.name(JAVA_COMMAND_LINE); - out.value(info.getJavaCommandLine()); - out.name(VM_NAME); - out.value(info.getVmName()); - out.name(VM_ARGUMENTS); - out.value(info.getVmArguments()); - out.name(VM_INFO); - out.value(info.getVmInfo()); - out.name(VM_VERSION); - out.value(info.getVmVersion()); - out.name(PROPERTIES_AS_ARRAY); - writeStringMap(out, info.getProperties()); - out.name(ENVIRONMENT_AS_ARRAY); - writeStringMap(out, info.getEnvironment()); - out.name(LOADED_NATIVE_LIBRARIES); - writeStringArray(out, info.getLoadedNativeLibraries()); - out.name(UID); - writeLong(out, info.getUid()); - out.name(USERNAME); - out.value(info.getUsername()); - - out.endObject(); - } - - private void writeStringMap(JsonWriter out, Map<String, String> map) throws IOException { - // Write contents of Map as an array of JSON objects - out.beginArray(); - - Set<Entry<String, String>> entries = map.entrySet(); - for (Map.Entry<String, String> entry : entries) { - // Create JSON object with key and value labeled as JSON names - out.beginObject(); - out.name(KEY); - out.value(entry.getKey()); - out.name(VALUE); - out.value(entry.getValue()); - out.endObject(); - } - - out.endArray(); - } - - private void writeStringArray(JsonWriter out, String[] array) throws IOException { - // Write String[] as JSON array - out.beginArray(); - - for (String item : array) { - out.value(item); - } - - out.endArray(); - } - - private static void writeLong(JsonWriter out, long value) throws IOException { - // Write MongoDB representation of a Long - out.beginObject(); - out.name(TYPE_LONG); - out.value(String.valueOf(value)); - out.endObject(); - } - - @Override - public List<VmInfo> read(JsonReader in) throws IOException { - throw new UnsupportedOperationException(); - } - - static class VmInfoUpdateTypeAdapter extends TypeAdapter<VmInfoUpdate> { - - private static final String SET = "set"; - - @Override - public void write(JsonWriter out, VmInfoUpdate value) throws IOException { - // List fields to update as part of a JSON object with name "set" - out.beginObject(); - out.name(SET); - - out.beginObject(); - out.name(STOP_TIME_STAMP); - writeLong(out, value.getStoppedTime()); - out.endObject(); - - out.endObject(); - } - - @Override - public VmInfoUpdate read(JsonReader in) throws IOException { - throw new UnsupportedOperationException(); - } - - } - -}
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/model/VmInfo.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,387 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.storage.model; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import com.redhat.thermostat.storage.core.Entity; -import com.redhat.thermostat.storage.core.Persist; - -@Entity -public class VmInfo extends BasePojo { - - public enum AliveStatus { - RUNNING, - EXITED, - /** - * We don't know what the status of this VM is. Possible cause: agent - * was shut down before the VM was. - */ - UNKNOWN, - } - - @Entity - public static class KeyValuePair implements Pojo { - - private String key; - private String value; - - public KeyValuePair() { - this(null, null); - } - - public KeyValuePair(String key, String value) { - this.key = key; - this.value = value; - } - - @Persist - public String getKey() { - return key; - } - - @Persist - public void setKey(String key) { - this.key = key; - } - - @Persist - public String getValue() { - return value; - } - - @Persist - public void setValue(String value) { - this.value = value; - } - - - } - - private String vmId; - private int vmPid = 0; - private long startTime = System.currentTimeMillis(); - private long stopTime = Long.MIN_VALUE; - private String javaVersion = "unknown"; - private String javaHome = "unknown"; - private String javaCommandLine = "unknown"; - private String mainClass = "unknown"; - private String vmName = "unknown"; - private String vmInfo = "unknown"; - private String vmVersion = "unknown"; - private String vmArguments = "unknown"; - private Map<String, String> properties = new HashMap<String, String>(); - private Map<String, String> environment = new HashMap<String, String>(); - private String[] loadedNativeLibraries; - private long uid; - private String username; - - public VmInfo() { - /* use defaults */ - super(null); - } - - public VmInfo(String writerId, String vmId, int vmPid, long startTime, long stopTime, - String javaVersion, String javaHome, - String mainClass, String commandLine, - String vmName, String vmInfo, String vmVersion, String vmArguments, - Map<String, String> properties, Map<String, String> environment, String[] loadedNativeLibraries, - long uid, String username) { - super(writerId); - this.vmId = vmId; - this.vmPid = vmPid; - this.startTime = startTime; - this.stopTime = stopTime; - this.javaVersion = javaVersion; - this.javaHome = javaHome; - this.mainClass = mainClass; - this.javaCommandLine = commandLine; - this.vmName = vmName; - this.vmInfo = vmInfo; - this.vmVersion = vmVersion; - this.vmArguments = vmArguments; - this.properties = properties; - this.environment = environment; - this.loadedNativeLibraries = loadedNativeLibraries; - this.uid = uid; - this.username = username; - } - - @Persist - public String getVmId() { - return vmId; - } - - @Persist - public void setVmId(String vmId) { - this.vmId = vmId; - } - - @Persist - public int getVmPid() { - return vmPid; - } - - @Persist - public void setVmPid(int vmPid) { - this.vmPid = vmPid; - } - - @Persist - public long getStartTimeStamp() { - return startTime; - } - - @Persist - public void setStartTimeStamp(long startTime) { - this.startTime = startTime; - } - - @Persist - public long getStopTimeStamp() { - return stopTime; - } - - @Persist - public void setStopTimeStamp(long stopTime) { - this.stopTime = stopTime; - } - - @Persist - public String getJavaVersion() { - return javaVersion; - } - - @Persist - public void setJavaVersion(String javaVersion) { - this.javaVersion = javaVersion; - } - - @Persist - public String getJavaHome() { - return javaHome; - } - - @Persist - public void setJavaHome(String javaHome) { - this.javaHome = javaHome; - } - - /** - * If java is invoked as {@code java -jar foo.jar}, then the main class name - * is {@code foo.jar}. - */ - @Persist - public String getMainClass() { - return mainClass; - } - - @Persist - public void setMainClass(String mainClass) { - this.mainClass = mainClass; - } - - @Persist - public String getJavaCommandLine() { - return javaCommandLine; - } - - @Persist - public void setJavaCommandLine(String javaCommandLine) { - this.javaCommandLine = javaCommandLine; - } - - @Persist - public String getVmName() { - return vmName; - } - - @Persist - public void setVmName(String vmName) { - this.vmName = vmName; - } - - @Persist - public String getVmArguments() { - return vmArguments; - } - - @Persist - public void setVmArguments(String vmArguments) { - this.vmArguments = vmArguments; - } - - @Persist - public String getVmInfo() { - return vmInfo; - } - - @Persist - public void setVmInfo(String vmInfo) { - this.vmInfo = vmInfo; - } - - @Persist - public String getVmVersion() { - return vmVersion; - } - - @Persist - public void setVmVersion(String vmVersion) { - this.vmVersion = vmVersion; - } - - /** - * @deprecated This can incorrectly show a VM as running when the actual - * status is unknown. Use {@link #isAlive(AgentInformation)} - * instead. - */ - @Deprecated - public boolean isAlive() { - return getStartTimeStamp() > getStopTimeStamp(); - } - - public AliveStatus isAlive(AgentInformation agentInfo) { - if (agentInfo.isAlive()) { - return (isAlive() ? AliveStatus.RUNNING : AliveStatus.EXITED); - } else { - return (isAlive() ? AliveStatus.UNKNOWN: AliveStatus.EXITED); - } - } - - public Map<String, String> getProperties() { - return properties; - } - - public void setProperties(Map<String, String> properties) { - this.properties = properties; - } - - @Persist - public KeyValuePair[] getPropertiesAsArray() { - return getMapAsArray(properties); - } - - @Persist - public void setPropertiesAsArray(KeyValuePair[] properties) { - this.properties = getArrayAsMap(properties); - } - - public Map<String, String> getEnvironment() { - return environment; - } - - public void setEnvironment(Map<String, String> environment) { - this.environment = environment; - } - - @Persist - public KeyValuePair[] getEnvironmentAsArray() { - return getMapAsArray(environment); - } - - @Persist - public void setEnvironmentAsArray(KeyValuePair[] environment) { - this.environment = getArrayAsMap(environment); - } - - private KeyValuePair[] getMapAsArray(Map<String, String> map) { - if (map == null) { - return null; - } - Set<String> keys = map.keySet(); - KeyValuePair[] tuples = new KeyValuePair[keys.size()]; - int i = 0; - for (String key: keys) { - tuples[i] = new KeyValuePair(key, map.get(key)); - i++; - } - return tuples; - } - - private Map<String,String> getArrayAsMap(KeyValuePair[] tuples) { - if (tuples == null) { - return null; - } - Map<String,String> map = new HashMap<>(); - for (KeyValuePair tuple : tuples) { - map.put(tuple.getKey(), tuple.getValue()); - } - return map; - } - - @Persist - public String[] getLoadedNativeLibraries() { - return loadedNativeLibraries; - } - - @Persist - public void setLoadedNativeLibraries(String[] loadedNativeLibraries) { - this.loadedNativeLibraries = loadedNativeLibraries; - } - - /** - * Returns the system user id for the owner of this JVM process, - * or -1 if an owner could not be found. - */ - @Persist - public long getUid() { - return uid; - } - - @Persist - public void setUid(long uid) { - this.uid = uid; - } - - /** - * Returns the system user name for the owner of this JVM process, - * or null if an owner could not be found. - */ - @Persist - public String getUsername() { - return username; - } - - @Persist - public void setUsername(String username) { - this.username = username; - } -} -
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/core/VmIdTest.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.storage.core; - -public class VmIdTest extends IdTest { - - @Override - protected VmId createId(String id) { return new VmId(id); } -}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/ActivatorTest.java Thu Jun 08 20:16:03 2017 +0200 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/ActivatorTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -51,11 +51,9 @@ import com.redhat.thermostat.storage.dao.AgentInfoDAO; import com.redhat.thermostat.storage.dao.BackendInfoDAO; import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO; -import com.redhat.thermostat.storage.dao.VmInfoDAO; import com.redhat.thermostat.storage.internal.dao.AgentInfoDAOImpl; import com.redhat.thermostat.storage.internal.dao.BackendInfoDAOImpl; import com.redhat.thermostat.storage.internal.dao.NetworkInterfaceInfoDAOImpl; -import com.redhat.thermostat.storage.internal.dao.VmInfoDAOImpl; import com.redhat.thermostat.testutils.StubBundleContext; public class ActivatorTest { @@ -69,7 +67,6 @@ assertTrue(context.isServiceRegistered(WriterID.class.getName(), WriterIDImpl.class)); assertTrue(context.isServiceRegistered(NetworkInterfaceInfoDAO.class.getName(), NetworkInterfaceInfoDAOImpl.class)); - assertTrue(context.isServiceRegistered(VmInfoDAO.class.getName(), VmInfoDAOImpl.class)); assertTrue(context.isServiceRegistered(AgentInfoDAO.class.getName(), AgentInfoDAOImpl.class)); assertTrue(context.isServiceRegistered(BackendInfoDAO.class.getName(), BackendInfoDAOImpl.class)); @@ -90,7 +87,6 @@ activator.stop(context); assertFalse(context.isServiceRegistered(NetworkInterfaceInfoDAO.class.getName(), NetworkInterfaceInfoDAOImpl.class)); - assertFalse(context.isServiceRegistered(VmInfoDAO.class.getName(), VmInfoDAOImpl.class)); assertFalse(context.isServiceRegistered(AgentInfoDAO.class.getName(), AgentInfoDAOImpl.class)); assertFalse(context.isServiceRegistered(BackendInfoDAO.class.getName(), BackendInfoDAOImpl.class)); assertFalse(context.isServiceRegistered(WriterID.class.getName(), WriterIDImpl.class)); @@ -114,7 +110,6 @@ activator.start(context); assertTrue(context.isServiceRegistered(NetworkInterfaceInfoDAO.class.getName(), NetworkInterfaceInfoDAOImpl.class)); - assertTrue(context.isServiceRegistered(VmInfoDAO.class.getName(), VmInfoDAOImpl.class)); assertTrue(context.isServiceRegistered(AgentInfoDAO.class.getName(), AgentInfoDAOImpl.class)); assertTrue(context.isServiceRegistered(BackendInfoDAO.class.getName(), BackendInfoDAOImpl.class)); assertTrue(context.isServiceRegistered(WriterID.class.getName(), WriterIDImpl.class)); @@ -127,7 +122,6 @@ activator.start(context); assertTrue(context.isServiceRegistered(NetworkInterfaceInfoDAO.class.getName(), NetworkInterfaceInfoDAOImpl.class)); - assertTrue(context.isServiceRegistered(VmInfoDAO.class.getName(), VmInfoDAOImpl.class)); assertTrue(context.isServiceRegistered(AgentInfoDAO.class.getName(), AgentInfoDAOImpl.class)); assertTrue(context.isServiceRegistered(BackendInfoDAO.class.getName(), BackendInfoDAOImpl.class)); assertTrue(context.isServiceRegistered(WriterID.class.getName(), WriterIDImpl.class));
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/VmInfoDAOTest.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,153 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.storage.internal.dao; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyListOf; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.client.api.Request; -import org.eclipse.jetty.client.util.StringContentProvider; -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.HttpStatus; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.redhat.thermostat.storage.dao.VmInfoDAO; -import com.redhat.thermostat.storage.internal.dao.VmInfoDAOImpl.HttpHelper; -import com.redhat.thermostat.storage.internal.dao.VmInfoDAOImpl.JsonHelper; -import com.redhat.thermostat.storage.internal.dao.VmInfoDAOImpl.VmInfoUpdate; -import com.redhat.thermostat.storage.model.VmInfo; - -public class VmInfoDAOTest { - - private static final String URL = "http://localhost:26000/api/v100/vm-info/systems/*/agents/foo-agent"; - private static final String UPDATE_URL = URL + "/jvms/vmId"; - private static final String SOME_JSON = "{\"some\" : \"json\"}"; - private static final String SOME_OTHER_JSON = "{\"some\" : {\"other\" : \"json\"}}"; - private static final String CONTENT_TYPE = "application/json"; - - private VmInfo info; - private JsonHelper jsonHelper; - private HttpHelper httpHelper; - private StringContentProvider contentProvider; - private Request request; - private ContentResponse response; - - @Before - public void setUp() throws Exception { - String vmId = "vmId"; - int vmPid = 1; - long startTime = 2L; - long stopTime = Long.MIN_VALUE; - String jVersion = "java 1.0"; - String jHome = "/path/to/jdk/home"; - String mainClass = "Hello.class"; - String commandLine = "World"; - String vmArgs = "-XX=+FastestJITPossible"; - String vmName = "Hotspot"; - String vmInfo = "Some info"; - String vmVersion = "1.0"; - Map<String, String> props = new HashMap<>(); - Map<String, String> env = new HashMap<>(); - String[] libs = new String[0]; - long uid = 2000L; - String username = "myUser"; - info = new VmInfo("foo-agent", vmId, vmPid, startTime, stopTime, jVersion, jHome, - mainClass, commandLine, vmName, vmInfo, vmVersion, vmArgs, - props, env, libs, uid, username); - - httpHelper = mock(HttpHelper.class); - contentProvider = mock(StringContentProvider.class); - when(httpHelper.createContentProvider(anyString())).thenReturn(contentProvider); - request = mock(Request.class); - when(httpHelper.newRequest(anyString())).thenReturn(request); - response = mock(ContentResponse.class); - when(response.getStatus()).thenReturn(HttpStatus.OK_200); - when(request.send()).thenReturn(response); - - jsonHelper = mock(JsonHelper.class); - when(jsonHelper.toJson(anyListOf(VmInfo.class))).thenReturn(SOME_JSON); - when(jsonHelper.toJson(any(VmInfoUpdate.class))).thenReturn(SOME_OTHER_JSON); - } - - @Test - public void testPutVmInfo() throws Exception { - VmInfoDAO dao = new VmInfoDAOImpl(httpHelper, jsonHelper); - dao.putVmInfo(info); - - verify(httpHelper).newRequest(URL); - verify(request).method(HttpMethod.POST); - verify(jsonHelper).toJson(eq(Arrays.asList(info))); - verify(httpHelper).createContentProvider(SOME_JSON); - verify(request).content(contentProvider, CONTENT_TYPE); - verify(request).send(); - verify(response).getStatus(); - } - - @Test - public void testPutVmStoppedTime() throws Exception { - VmInfoDAO dao = new VmInfoDAOImpl(httpHelper, jsonHelper); - dao.putVmStoppedTime("foo-agent", "vmId", 3L); - - verify(httpHelper).newRequest(UPDATE_URL); - verify(request).method(HttpMethod.PUT); - - ArgumentCaptor<VmInfoUpdate> updateCaptor = ArgumentCaptor.forClass(VmInfoUpdate.class); - verify(jsonHelper).toJson(updateCaptor.capture()); - VmInfoUpdate update = updateCaptor.getValue(); - assertEquals(3L, update.getStoppedTime()); - - verify(httpHelper).createContentProvider(SOME_OTHER_JSON); - verify(request).content(contentProvider, CONTENT_TYPE); - verify(request).send(); - verify(response).getStatus(); - } - -} -
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/VmInfoTypeAdapterTest.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.storage.internal.dao; - -import static org.junit.Assert.assertEquals; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.junit.Test; - -import com.redhat.thermostat.storage.internal.dao.VmInfoDAOImpl.VmInfoUpdate; -import com.redhat.thermostat.storage.internal.dao.VmInfoTypeAdapter.VmInfoUpdateTypeAdapter; -import com.redhat.thermostat.storage.model.VmInfo; - -public class VmInfoTypeAdapterTest { - - @Test - public void testWrite() throws Exception { - VmInfoTypeAdapter adapter = new VmInfoTypeAdapter(); - final String expected = "[{\"agentId\":\"agent1\",\"vmId\":\"vm1\",\"vmPid\":8000," - + "\"startTimeStamp\":{\"$numberLong\":\"50000\"},\"stopTimeStamp\":" - + "{\"$numberLong\":\"-9223372036854775808\"},\"javaVersion\":\"1.8.0\"," - + "\"javaHome\":\"/path/to/java\",\"mainClass\":\"myClass\",\"javaCommandLine\":\"java myClass\"," - + "\"vmName\":\"myJVM\",\"vmArguments\":\"-Dhello\",\"vmInfo\":\"interesting\"," - + "\"vmVersion\":\"1800\",\"propertiesAsArray\":[{\"key\":\"A\",\"value\":\"B\"}," - + "{\"key\":\"C\",\"value\":\"D\"}],\"environmentAsArray\":[{\"key\":\"E\",\"value\":\"F\"}," - + "{\"key\":\"G\",\"value\":\"H\"}],\"loadedNativeLibraries\":[],\"uid\":{\"$numberLong\":\"1234\"}," - + "\"username\":\"test\"}," - + "{\"agentId\":\"agent2\",\"vmId\":\"vm2\",\"vmPid\":9000,\"startTimeStamp\":" - + "{\"$numberLong\":\"100000\"},\"stopTimeStamp\":{\"$numberLong\":\"200000\"}," - + "\"javaVersion\":\"1.7.0\",\"javaHome\":\"/path/to/jre\",\"mainClass\":\"myOtherClass\"," - + "\"javaCommandLine\":\"otherClass.sh\",\"vmName\":\"myOtherJVM\",\"vmArguments\":\"-Dworld\"," - + "\"vmInfo\":\"info\",\"vmVersion\":\"1700\",\"propertiesAsArray\":[],\"environmentAsArray\":" - + "[{\"key\":\"A\",\"value\":\"B\"},{\"key\":\"C\",\"value\":\"D\"}]," - + "\"loadedNativeLibraries\":[\"libhello\",\"libworld\"],\"uid\":{\"$numberLong\":\"5678\"}" - + ",\"username\":\"user\"}]"; - - final Map<String, String> props = new HashMap<>(); - props.put("A", "B"); - props.put("C", "D"); - final Map<String, String> env = new HashMap<>(); - env.put("E", "F"); - env.put("G", "H"); - VmInfo first = new VmInfo("agent1", "vm1", 8000, 50000L, Long.MIN_VALUE, "1.8.0", "/path/to/java", "myClass", - "java myClass", "myJVM", "interesting", "1800", "-Dhello", props, env, new String[0], 1234L, "test"); - - final Map<String, String> props2 = new HashMap<>(); - final Map<String, String> env2 = new HashMap<>(); - env2.put("A", "B"); - env2.put("C", "D"); - final String[] libs = { "libhello", "libworld" }; - VmInfo second = new VmInfo("agent2", "vm2", 9000, 100000L, 200000L, "1.7.0", "/path/to/jre", "myOtherClass", - "otherClass.sh", "myOtherJVM", "info", "1700", "-Dworld", props2, env2, libs, 5678L, "user"); - List<VmInfo> infos = Arrays.asList(first, second); - - String json = adapter.toJson(infos); - assertEquals(expected, json); - } - - @Test - public void testUpdate() throws Exception { - VmInfoUpdateTypeAdapter adapter = new VmInfoUpdateTypeAdapter(); - final String expected = "{\"set\":{\"stopTimeStamp\":{\"$numberLong\":\"5000\"}}}"; - - VmInfoUpdate update = new VmInfoUpdate(5000L); - String json = adapter.toJson(update); - assertEquals(expected, json); - } - -}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/model/PojoModelInstantiationTest.java Thu Jun 08 20:16:03 2017 +0200 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/model/PojoModelInstantiationTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -44,7 +44,6 @@ AgentInformation.class, BackendInformation.class, NetworkInterfaceInfo.class, - VmInfo.class, }; @Override
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/InfoBuilderFactoryImpl.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.system.internal; - -import com.redhat.thermostat.backend.system.internal.models.InfoBuilderFactory; -import com.redhat.thermostat.backend.system.internal.models.ProcessEnvironmentBuilder; -import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder; -import com.redhat.thermostat.common.portability.ProcessUserInfoBuilderFactory; -import com.redhat.thermostat.common.portability.UserNameUtil; -import com.redhat.thermostat.common.portability.linux.ProcDataSource; - -/** - * Allows callers to access Windows-specific builders portably - */ -public class InfoBuilderFactoryImpl implements InfoBuilderFactory { - - public InfoBuilderFactoryImpl() { - } - - public ProcessEnvironmentBuilder createProcessEnvironmentBuilder() { - return new ProcessEnvironmentBuilderImpl(); - } - - public ProcessUserInfoBuilder createProcessUserInfoBuilder(final UserNameUtil userNameUtil) { - return ProcessUserInfoBuilderFactory.createBuilder(new ProcDataSource(), userNameUtil); - } -}
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/JvmStatDataExtractor.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.system.internal; - -import sun.jvmstat.monitor.MonitorException; -import sun.jvmstat.monitor.MonitoredVm; -import sun.jvmstat.monitor.MonitoredVmUtil; - -/** - * A helper class to provide type-safe access to commonly used jvmstat monitors - * <p> - * Implementation details: For local vms, jvmstat uses a ByteBuffer - * corresponding to mmap()ed hsperfdata file. The hsperfdata file is updated - * asynchronously by the vm that created the file. The polling that jvmstat api - * provides is merely an abstraction over this (possibly always up-to-date) - * ByteBuffer. So the data this class extracts is as current as possible, and - * does not correspond to when the jvmstat update events fired. - */ -public class JvmStatDataExtractor { - - /* - * Note, there may be a performance issue to consider here. We have a lot of - * string constants. When we start adding some of the more heavyweight - * features, and running into CPU issues this may need to be reconsidered in - * order to avoid the String pool overhead. See also: - * http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#intern() - */ - - private final MonitoredVm vm; - - public JvmStatDataExtractor(MonitoredVm vm) { - this.vm = vm; - } - - public String getCommandLine() throws MonitorException { - return MonitoredVmUtil.commandLine(vm); - } - - public String getMainClass() throws MonitorException { - return MonitoredVmUtil.mainClass(vm, true); - } - - public String getJavaVersion() throws MonitorException { - return (String) vm.findByName("java.property.java.version").getValue(); - } - - public String getJavaHome() throws MonitorException { - return (String) vm.findByName("java.property.java.home").getValue(); - } - - public String getVmName() throws MonitorException { - return (String) vm.findByName("java.property.java.vm.name").getValue(); - } - - public String getVmInfo() throws MonitorException { - return (String) vm.findByName("java.property.java.vm.info").getValue(); - } - - public String getVmVersion() throws MonitorException { - return (String) vm.findByName("java.property.java.vm.version").getValue(); - } - - public String getVmArguments() throws MonitorException { - return MonitoredVmUtil.jvmArgs(vm); - } - - public long getVmStartTime() throws MonitorException { - return (long) vm.findByName("sun.rt.vmInitDoneTime").getValue(); - } - -} -
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/JvmStatHostListener.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,188 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.system.internal; - -import java.net.URISyntaxException; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.agent.VmBlacklist; -import com.redhat.thermostat.agent.VmStatusListener.Status; -import com.redhat.thermostat.backend.system.internal.models.InfoBuilderFactory; -import com.redhat.thermostat.common.Pair; -import com.redhat.thermostat.common.portability.ProcessUserInfo; -import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.storage.core.WriterID; -import com.redhat.thermostat.storage.dao.VmInfoDAO; -import com.redhat.thermostat.storage.model.VmInfo; - -import sun.jvmstat.monitor.MonitorException; -import sun.jvmstat.monitor.MonitoredHost; -import sun.jvmstat.monitor.MonitoredVm; -import sun.jvmstat.monitor.VmIdentifier; -import sun.jvmstat.monitor.event.HostEvent; -import sun.jvmstat.monitor.event.HostListener; -import sun.jvmstat.monitor.event.VmStatusChangeEvent; - -class JvmStatHostListener implements HostListener { - - private static final Logger logger = LoggingUtils.getLogger(JvmStatHostListener.class); - - private final VmInfoDAO vmInfoDAO; - private final VmStatusChangeNotifier notifier; - private final ProcessUserInfoBuilder userInfoBuilder; - private final WriterID writerId; - private Map<Integer, Pair<String, MonitoredVm>> monitoredVms = new HashMap<>(); - private final VmBlacklist blacklist; - - JvmStatHostListener(VmInfoDAO vmInfoDAO, VmStatusChangeNotifier notifier, - ProcessUserInfoBuilder userInfoBuilder, WriterID writerId, - VmBlacklist blacklist) { - this.vmInfoDAO = vmInfoDAO; - this.notifier = notifier; - this.userInfoBuilder = userInfoBuilder; - this.writerId = writerId; - this.blacklist = blacklist; - } - - @Override - public void disconnected(HostEvent event) { - logger.warning("Disconnected from host"); - } - - @SuppressWarnings("unchecked") // Unchecked casts to (Set<Integer>). - @Override - public void vmStatusChanged(VmStatusChangeEvent event) { - MonitoredHost host = event.getMonitoredHost(); - - for (Integer newVm : (Set<Integer>) event.getStarted()) { - try { - logger.fine("New vm: " + newVm); - sendNewVM(newVm, host); - } catch (MonitorException e) { - logger.log(Level.WARNING, "error getting info for new vm " + newVm, e); - } catch (URISyntaxException e) { - logger.log(Level.WARNING, "error getting info for new vm " + newVm, e); - } - } - - for (Integer stoppedVm : (Set<Integer>) event.getTerminated()) { - try { - logger.fine("stopped vm: " + stoppedVm); - sendStoppedVM(stoppedVm, host); - } catch (URISyntaxException e) { - logger.log(Level.WARNING, "error getting info for stopped vm " + stoppedVm, e); - } catch (MonitorException e) { - logger.log(Level.WARNING, "error getting info for stopped vm " + stoppedVm, e); - } - } - } - - private void sendNewVM(Integer vmPid, MonitoredHost host) - throws MonitorException, URISyntaxException { - // Propagate any MonitorException, and do not notify Backends or remember - // VMs when we fail to extract the necessary information. - // http://icedtea.classpath.org/pipermail/thermostat/2013-November/008702.html - MonitoredVm vm = host.getMonitoredVm(host.getHostIdentifier().resolve( - new VmIdentifier(vmPid.toString()))); - if (vm != null) { - JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm); - String vmId = UUID.randomUUID().toString(); - long stopTime = Long.MIN_VALUE; - VmInfo info = createVmInfo(vmId, vmPid, stopTime, extractor); - - // Check blacklist - if (!blacklist.isBlacklisted(info.getMainClass())) { - vmInfoDAO.putVmInfo(info); - - notifier.notifyVmStatusChange(Status.VM_STARTED, vmId, vmPid); - logger.finer("Sent VM_STARTED messsage"); - - monitoredVms.put(vmPid, new Pair<>(vmId, vm)); - } - else { - logger.info("Skipping VM: " + vmPid); - } - } - } - - VmInfo createVmInfo(String vmId, Integer vmPid, long stopTime, - JvmStatDataExtractor extractor) throws MonitorException { - Map<String, String> properties = new HashMap<String, String>(); - Map<String, String> environment = InfoBuilderFactory.INSTANCE.createProcessEnvironmentBuilder().build(vmPid); - // TODO actually figure out the loaded libraries. - String[] loadedNativeLibraries = new String[0]; - ProcessUserInfo userInfo = userInfoBuilder.build(vmPid); - VmInfo info = new VmInfo(writerId.getWriterID(), vmId, vmPid, extractor.getVmStartTime(), stopTime, - extractor.getJavaVersion(), extractor.getJavaHome(), - extractor.getMainClass(), extractor.getCommandLine(), - extractor.getVmName(), extractor.getVmInfo(), extractor.getVmVersion(), extractor.getVmArguments(), - properties, environment, loadedNativeLibraries, userInfo.getUid(), userInfo.getUsername()); - return info; - } - - private void sendStoppedVM(Integer vmPid, MonitoredHost host) throws URISyntaxException, MonitorException { - - VmIdentifier resolvedVmID = host.getHostIdentifier().resolve(new VmIdentifier(vmPid.toString())); - if (resolvedVmID != null && monitoredVms.containsKey(vmPid)) { - Pair<String, MonitoredVm> vmData = monitoredVms.remove(vmPid); - - String vmId = vmData.getFirst(); - notifier.notifyVmStatusChange(Status.VM_STOPPED, vmId, vmPid); - - long stopTime = System.currentTimeMillis(); - vmInfoDAO.putVmStoppedTime(writerId.getWriterID(), vmId, stopTime); - - MonitoredVm vm = vmData.getSecond(); - vm.detach(); - } - } - - /* - * For testing purposes only. - */ - Map<Integer, Pair<String, MonitoredVm>> getMonitoredVms() { - return monitoredVms; - } - -} -
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/ProcessEnvironmentBuilderImpl.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.system.internal; - -import com.redhat.thermostat.backend.system.internal.models.ProcessEnvironmentBuilder; -import com.redhat.thermostat.common.portability.PortableProcess; -import com.redhat.thermostat.common.portability.PortableProcessFactory; - -import java.util.Map; - -/** - * Build process environment information via portable helper classes - */ -class ProcessEnvironmentBuilderImpl implements ProcessEnvironmentBuilder { - - private final PortableProcess helper; - - ProcessEnvironmentBuilderImpl() { - this(PortableProcessFactory.getInstance()); - } - - ProcessEnvironmentBuilderImpl(PortableProcess wh) { - helper = wh; - } - - @Override - public Map<String, String> build(int pid) { - return helper.getEnvironment(pid); - } -}
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/SystemBackend.java Thu Jun 08 20:16:03 2017 +0200 +++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/SystemBackend.java Fri Jun 09 16:38:44 2017 +0200 @@ -36,64 +36,37 @@ package com.redhat.thermostat.backend.system.internal; -import java.net.URISyntaxException; import java.util.Timer; import java.util.TimerTask; -import java.util.logging.Level; import java.util.logging.Logger; -import com.redhat.thermostat.agent.VmBlacklist; import com.redhat.thermostat.backend.BaseBackend; -import com.redhat.thermostat.backend.system.internal.models.InfoBuilderFactory; import com.redhat.thermostat.common.Version; -import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder; -import com.redhat.thermostat.common.portability.UserNameUtil; import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.storage.core.WriterID; import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO; -import com.redhat.thermostat.storage.dao.VmInfoDAO; import com.redhat.thermostat.storage.model.NetworkInterfaceInfo; -import sun.jvmstat.monitor.HostIdentifier; -import sun.jvmstat.monitor.MonitorException; -import sun.jvmstat.monitor.MonitoredHost; - public class SystemBackend extends BaseBackend { private static final Logger logger = LoggingUtils.getLogger(SystemBackend.class); private NetworkInterfaceInfoDAO networkInterfaces; - private VmInfoDAO vmInfoDAO; private long procCheckInterval = 1000; // TODO make this configurable. private Timer timer = null; - private HostIdentifier hostId = null; - private MonitoredHost host = null; - private JvmStatHostListener hostListener = null; + private final NetworkInfoBuilder networkInfoBuilder; - private final NetworkInfoBuilder networkInfoBuilder; - private final ProcessUserInfoBuilder userInfoBuilder; - private final VmStatusChangeNotifier notifier; - private final WriterID writerId; - private final VmBlacklist blacklist; - - public SystemBackend(NetworkInterfaceInfoDAO netInfoDAO, VmInfoDAO vmInfoDAO, - Version version, VmStatusChangeNotifier notifier, UserNameUtil userNameUtil, WriterID writerId, - VmBlacklist blacklist) { + public SystemBackend(NetworkInterfaceInfoDAO netInfoDAO, + Version version, WriterID writerId) { super("System Backend", "Gathers basic information from the system", - "Red Hat, Inc.", + "Red Hat, Inc.", "1.0", true); this.networkInterfaces = netInfoDAO; - this.vmInfoDAO = vmInfoDAO; - this.notifier = notifier; - this.writerId = writerId; - this.blacklist = blacklist; setVersion(version.getVersionNumber()); - - userInfoBuilder = InfoBuilderFactory.INSTANCE.createProcessUserInfoBuilder(userNameUtil); networkInfoBuilder = new NetworkInfoBuilder(writerId); } @@ -117,18 +90,6 @@ } }, 0, procCheckInterval); - try { - hostId = new HostIdentifier((String) null); - hostListener = new JvmStatHostListener(vmInfoDAO, notifier, - userInfoBuilder, writerId, blacklist); - host = MonitoredHost.getMonitoredHost(hostId); - host.addHostListener(hostListener); - } catch (MonitorException me) { - logger.log(Level.WARNING, "problems with connecting jvmstat to local machine", me); - } catch (URISyntaxException use) { - logger.log(Level.WARNING, "problems with connecting jvmstat to local machine", use); - } - return true; } @@ -141,14 +102,6 @@ timer.cancel(); timer = null; - try { - host.removeHostListener(hostListener); - } catch (MonitorException me) { - logger.log(Level.INFO, "something went wrong in jvmstat's listening to this host"); - } - host = null; - hostId = null; - return true; }
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/SystemBackendActivator.java Thu Jun 08 20:16:03 2017 +0200 +++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/SystemBackendActivator.java Fri Jun 09 16:38:44 2017 +0200 @@ -40,7 +40,6 @@ import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; -import com.redhat.thermostat.agent.VmBlacklist; import com.redhat.thermostat.backend.Backend; import com.redhat.thermostat.backend.BackendService; import com.redhat.thermostat.common.MultipleServiceTracker; @@ -50,7 +49,6 @@ import com.redhat.thermostat.common.portability.UserNameUtil; import com.redhat.thermostat.storage.core.WriterID; import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO; -import com.redhat.thermostat.storage.dao.VmInfoDAO; @SuppressWarnings("rawtypes") public class SystemBackendActivator implements BundleActivator { @@ -58,33 +56,25 @@ private MultipleServiceTracker tracker; private SystemBackend backend; private ServiceRegistration reg; - private VmStatusChangeNotifier notifier; - + @Override public void start(final BundleContext context) throws Exception { - - notifier = new VmStatusChangeNotifier(context); - notifier.start(); - + Class<?>[] deps = new Class<?>[] { BackendService.class, NetworkInterfaceInfoDAO.class, - VmInfoDAO.class, UserNameUtil.class, WriterID.class, // system backend uses it - VmBlacklist.class, }; tracker = new MultipleServiceTracker(context, deps, new Action() { @Override public void dependenciesAvailable(DependencyProvider services) { NetworkInterfaceInfoDAO netInfoDAO = services.get(NetworkInterfaceInfoDAO.class); - VmInfoDAO vmInfoDAO = services.get(VmInfoDAO.class); - UserNameUtil userNameUtil = services.get(UserNameUtil.class); Version version = new Version(context.getBundle()); WriterID id = services.get(WriterID.class); - VmBlacklist blacklist = services.get(VmBlacklist.class); - backend = new SystemBackend(netInfoDAO, vmInfoDAO, version, notifier, - userNameUtil, id, blacklist); +// UserNameUtil userNameUtil = services.get(UserNameUtil.class); +// VmBlacklist blacklist = services.get(VmBlacklist.class); + backend = new SystemBackend(netInfoDAO, version, id); reg = context.registerService(Backend.class, backend, null); } @@ -107,7 +97,6 @@ backend.deactivate(); } tracker.close(); - notifier.stop(); } }
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/VmStatusChangeNotifier.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,139 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.system.internal; - -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.ConcurrentHashMap; - -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.util.tracker.ServiceTracker; - -import com.redhat.thermostat.agent.VmStatusListener; -import com.redhat.thermostat.agent.VmStatusListener.Status; - -/** - * Notifies any and all {@link VmStatusListener} registered as OSGi Services - * about VM status changes: {@link VmStatusListener.Status#VM_STARTED} and - * {@link VmStatusListener.Status#VM_STOPPED}. - * <p> - * Any listeners registered after a {@link VmStatusListener.Status#VM_STARTED} - * was delivered receive a {@link VmStatusListener.Status#VM_ACTIVE} event - * instead as an indication that a VM was started at some unknown point - * previously. - */ -public class VmStatusChangeNotifier { - - private final Object listenerLock = new Object(); - private final Map<Integer, String> activePids; - private final Map<VmStatusListener, Set<Integer>> listeners = new ConcurrentHashMap<>(); - - private final ServiceTracker tracker; - - public VmStatusChangeNotifier(BundleContext bundleContext) { - this.activePids = new HashMap<>(); - - tracker = new ServiceTracker(bundleContext, VmStatusListener.class, null) { - @Override - public VmStatusListener addingService(ServiceReference reference) { - VmStatusListener listener = (VmStatusListener) super.addingService(reference); - - synchronized (listenerLock) { - Set<Integer> notifiedAbout = new TreeSet<>(); - for (Entry<Integer, String> entry : activePids.entrySet()) { - Integer pid = entry.getKey(); - listener.vmStatusChanged(Status.VM_ACTIVE, entry.getValue(), pid); - notifiedAbout.add(pid); - } - - listeners.put(listener, notifiedAbout); - } - - return listener; - } - - @Override - public void removedService(ServiceReference reference, - Object service) { - VmStatusListener listener = (VmStatusListener) service; - listeners.remove(listener); - super.removedService(reference, service); - } - }; - } - - public void start() { - tracker.open(); - } - - public void stop() { - tracker.close(); - } - - /** - * Notify all registered listeners about a Vm status change. - * - * @param newStatus either {@link VmStatusListener.Status#VM_STARTED} or - * {@link VmStatusListener.Status#VM_STOPPED} - * @param vmId unique identifier for the VM - * @param pid process ID for the VM - */ - public void notifyVmStatusChange(VmStatusListener.Status newStatus, String vmId, int pid) { - if (newStatus == Status.VM_ACTIVE) { - throw new IllegalArgumentException("Dont pass in " + Status.VM_ACTIVE + ", that will be handled automatically"); - } - - synchronized (listenerLock) { - for (Entry<VmStatusListener, Set<Integer>> entry : listeners.entrySet()) { - entry.getKey().vmStatusChanged(newStatus, vmId, pid); - entry.getValue().add(pid); - } - - if (newStatus == Status.VM_STARTED) { - activePids.put(pid, vmId); - } else { - activePids.remove(pid); - } - } - } - -} -
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/models/InfoBuilderFactory.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.system.internal.models; - -import com.redhat.thermostat.backend.system.internal.InfoBuilderFactoryImpl; -import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder; -import com.redhat.thermostat.common.portability.UserNameUtil; - -/** - * Allows callers to access OS-specific builders portably - */ -public interface InfoBuilderFactory { - - static InfoBuilderFactory INSTANCE = new InfoBuilderFactoryImpl(); - - public ProcessEnvironmentBuilder createProcessEnvironmentBuilder(); - - public ProcessUserInfoBuilder createProcessUserInfoBuilder(final UserNameUtil userNameUtil); -}
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/internal/models/ProcessEnvironmentBuilder.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.system.internal.models; - -import java.util.Map; - -/** - * Interface for fetching a process environment - * An environment is represented as a map of name-value pairs - */ -public interface ProcessEnvironmentBuilder { - Map<String,String> build(int pid); -}
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/InfoBuilderFactoryTest.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.system.internal; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -import com.redhat.thermostat.backend.system.internal.models.InfoBuilderFactory; -import com.redhat.thermostat.backend.system.internal.models.ProcessEnvironmentBuilder; - -public class InfoBuilderFactoryTest { - - @Test - public void testCreateProcessEnvironmentBuilder() { - final InfoBuilderFactory builder = new InfoBuilderFactoryImpl(); - final ProcessEnvironmentBuilder hib = builder.createProcessEnvironmentBuilder(); - assertNotNull(hib); - assertTrue(hib instanceof ProcessEnvironmentBuilderImpl); - } -}
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/JvmStatDataExtractorTest.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,167 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.system.internal; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import org.junit.Test; - -import sun.jvmstat.monitor.MonitorException; -import sun.jvmstat.monitor.MonitoredVm; -import sun.jvmstat.monitor.StringMonitor; - -public class JvmStatDataExtractorTest { - - private MonitoredVm buildStringMonitoredVm(String monitorName, String monitorReturn) throws MonitorException { - final StringMonitor monitor = mock(StringMonitor.class); - when(monitor.stringValue()).thenReturn(monitorReturn); - when(monitor.getValue()).thenReturn(monitorReturn); - MonitoredVm vm = mock(MonitoredVm.class); - when(vm.findByName(monitorName)).thenReturn(monitor); - return vm; - } - - @Test - public void testCommandLine() throws MonitorException { - final String MONITOR_NAME = "sun.rt.javaCommand"; - final String MONITOR_VALUE = "command line java"; - MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE); - - JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm); - String returned = extractor.getCommandLine(); - - verify(vm).findByName(eq(MONITOR_NAME)); - assertEquals(MONITOR_VALUE, returned); - } - - @Test - public void testMainClass() throws MonitorException { - final String MONITOR_NAME = "sun.rt.javaCommand"; - final String MONITOR_VALUE = "some.package.Main"; - MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE); - - JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm); - String returned = extractor.getMainClass(); - - verify(vm).findByName(eq(MONITOR_NAME)); - assertEquals(MONITOR_VALUE, returned); - } - - @Test - public void testJavaVersion() throws MonitorException { - final String MONITOR_NAME = "java.property.java.version"; - final String MONITOR_VALUE = "some java version"; - MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE); - - JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm); - String returned = extractor.getJavaVersion(); - - verify(vm).findByName(eq(MONITOR_NAME)); - assertEquals(MONITOR_VALUE, returned); - } - - @Test - public void testJavaHome() throws MonitorException { - final String MONITOR_NAME = "java.property.java.home"; - final String MONITOR_VALUE = "${java.home}"; - MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE); - - JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm); - String returned = extractor.getJavaHome(); - - verify(vm).findByName(eq(MONITOR_NAME)); - assertEquals(MONITOR_VALUE, returned); - } - - @Test - public void testVmName() throws MonitorException { - final String MONITOR_NAME = "java.property.java.vm.name"; - final String MONITOR_VALUE = "${vm.name}"; - MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE); - - JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm); - String returned = extractor.getVmName(); - - verify(vm).findByName(eq(MONITOR_NAME)); - assertEquals(MONITOR_VALUE, returned); - } - - @Test - public void testVmInfo() throws MonitorException { - final String MONITOR_NAME = "java.property.java.vm.info"; - final String MONITOR_VALUE = "${vm.info}"; - MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE); - - JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm); - String returned = extractor.getVmInfo(); - - verify(vm).findByName(eq(MONITOR_NAME)); - assertEquals(MONITOR_VALUE, returned); - } - - @Test - public void testVmVersion() throws MonitorException { - final String MONITOR_NAME = "java.property.java.vm.version"; - final String MONITOR_VALUE = "${vm.version}"; - MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE); - - JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm); - String returned = extractor.getVmVersion(); - - verify(vm).findByName(eq(MONITOR_NAME)); - assertEquals(MONITOR_VALUE, returned); - } - - @Test - public void testVmArguments() throws MonitorException { - final String MONITOR_NAME = "java.rt.vmArgs"; - final String MONITOR_VALUE = "${vm.arguments}"; - MonitoredVm vm = buildStringMonitoredVm(MONITOR_NAME, MONITOR_VALUE); - - JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm); - String returned = extractor.getVmArguments(); - - verify(vm).findByName(eq(MONITOR_NAME)); - assertEquals(MONITOR_VALUE, returned); - } - -} -
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/JvmStatHostListenerTest.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,277 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.system.internal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.AdditionalMatchers.not; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isA; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.net.URISyntaxException; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.redhat.thermostat.agent.VmBlacklist; -import com.redhat.thermostat.agent.VmStatusListener.Status; -import com.redhat.thermostat.common.portability.ProcessUserInfo; -import com.redhat.thermostat.common.portability.ProcessUserInfoBuilder; -import com.redhat.thermostat.storage.core.WriterID; -import com.redhat.thermostat.storage.dao.VmInfoDAO; -import com.redhat.thermostat.storage.model.VmInfo; - -import sun.jvmstat.monitor.HostIdentifier; -import sun.jvmstat.monitor.Monitor; -import sun.jvmstat.monitor.MonitorException; -import sun.jvmstat.monitor.MonitoredHost; -import sun.jvmstat.monitor.MonitoredVm; -import sun.jvmstat.monitor.StringMonitor; -import sun.jvmstat.monitor.VmIdentifier; -import sun.jvmstat.monitor.event.VmStatusChangeEvent; - -public class JvmStatHostListenerTest { - - private static String INFO_CMDLINE = "/path/to/executable command line args"; - private static String INFO_JAVAHOME = "/path/to/java"; - private static String INFO_JAVAVER = "1.9001"; - private static String INFO_MAINCLASS = "MyMainClass"; - private static String INFO_VMARGS = "-Xarg1 -Xarg2"; - private static String INFO_VMINFO = "Info"; - private static String INFO_VMNAME = "MyJVM"; - private static String INFO_VMVER = "90.01"; - private static long INFO_VMUSERID = 2000; - private static String INFO_VMUSERNAME = "User"; - private static final long INFO_STARTTIME = Long.MIN_VALUE; - - private JvmStatHostListener hostListener; - private MonitoredHost host; - private MonitoredVm monitoredVm1; - private MonitoredVm monitoredVm2; - private JvmStatDataExtractor extractor; - private VmInfoDAO vmInfoDAO; - private VmStatusChangeNotifier notifier; - private VmBlacklist blacklist; - - @Before - public void setup() throws MonitorException, URISyntaxException { - vmInfoDAO = mock(VmInfoDAO.class); - notifier = mock(VmStatusChangeNotifier.class); - - ProcessUserInfoBuilder userInfoBuilder = mock(ProcessUserInfoBuilder.class); - ProcessUserInfo userInfo = new ProcessUserInfo(INFO_VMUSERID, INFO_VMUSERNAME); - when(userInfoBuilder.build(any(int.class))).thenReturn(userInfo); - - WriterID id = mock(WriterID.class); - blacklist = mock(VmBlacklist.class); - hostListener = new JvmStatHostListener(vmInfoDAO, notifier, userInfoBuilder, id, blacklist); - - host = mock(MonitoredHost.class); - HostIdentifier hostId = mock(HostIdentifier.class); - monitoredVm1 = mock(MonitoredVm.class); - monitoredVm2 = mock(MonitoredVm.class); - StringMonitor monitor = mock(StringMonitor.class); - Monitor monitor2 = mock(Monitor.class); - VmIdentifier vmId1 = new VmIdentifier("1"); - VmIdentifier vmId2 = new VmIdentifier("2"); - - when(monitor2.getValue()).thenReturn(100l); - when(host.getHostIdentifier()).thenReturn(hostId); - when(host.getMonitoredVm(eq(vmId1))).thenReturn(monitoredVm1); - when(host.getMonitoredVm(eq(vmId2))).thenReturn(monitoredVm2); - when(hostId.resolve(eq(vmId1))).thenReturn(vmId1); - when(hostId.resolve(eq(vmId2))).thenReturn(vmId2); - when(monitoredVm1.findByName("sun.rt.vmInitDoneTime")).thenReturn(monitor2); - when(monitoredVm2.findByName("sun.rt.vmInitDoneTime")).thenReturn(monitor2); - when(monitoredVm1.findByName(not(eq("sun.rt.vmInitDoneTime")))).thenReturn(monitor); - when(monitoredVm2.findByName(not(eq("sun.rt.vmInitDoneTime")))).thenReturn(monitor); - when(monitor.stringValue()).thenReturn("test"); - when(monitor.getValue()).thenReturn("test"); - extractor = mock(JvmStatDataExtractor.class); - - when(extractor.getCommandLine()).thenReturn(INFO_CMDLINE); - when(extractor.getJavaHome()).thenReturn(INFO_JAVAHOME); - when(extractor.getJavaVersion()).thenReturn(INFO_JAVAVER); - when(extractor.getMainClass()).thenReturn(INFO_MAINCLASS); - when(extractor.getVmArguments()).thenReturn(INFO_VMARGS); - when(extractor.getVmInfo()).thenReturn(INFO_VMINFO); - when(extractor.getVmName()).thenReturn(INFO_VMNAME); - when(extractor.getVmVersion()).thenReturn(INFO_VMVER); - when(extractor.getVmStartTime()).thenReturn(INFO_STARTTIME); - } - - @Test - public void testNewVM() throws InterruptedException, MonitorException { - startVMs(); - - assertTrue(hostListener.getMonitoredVms().containsKey(1)); - assertTrue(hostListener.getMonitoredVms().containsKey(2)); - assertEquals(monitoredVm1, hostListener.getMonitoredVms().get(1).getSecond()); - assertEquals(monitoredVm2, hostListener.getMonitoredVms().get(2).getSecond()); - - // Check valid UUIDs - UUID uuid1 = UUID.fromString(hostListener.getMonitoredVms().get(1).getFirst()); - UUID uuid2 = UUID.fromString(hostListener.getMonitoredVms().get(2).getFirst()); - assertFalse(uuid1.equals(uuid2)); - - verify(notifier, times(2)).notifyVmStatusChange(eq(Status.VM_STARTED), anyString(), (isA(Integer.class))); - } - - @Test - public void testNewVMBlackListed() throws InterruptedException, MonitorException { - when(blacklist.isBlacklisted(anyString())).thenReturn(true).thenReturn(false); - startVMs(); - - assertFalse(hostListener.getMonitoredVms().containsKey(1)); - assertTrue(hostListener.getMonitoredVms().containsKey(2)); - assertEquals(monitoredVm2, hostListener.getMonitoredVms().get(2).getSecond()); - - UUID uuid = UUID.fromString(hostListener.getMonitoredVms().get(2).getFirst()); - verify(notifier).notifyVmStatusChange(eq(Status.VM_STARTED), eq(uuid.toString()), (isA(Integer.class))); - } - - @Test - public void testStoppedVM() throws InterruptedException, MonitorException { - final Set<Integer> stopped = new HashSet<>(); - stopped.add(1); - - startVMs(); - - // Trigger a change event - VmStatusChangeEvent event = mock(VmStatusChangeEvent.class); - when(event.getMonitoredHost()).thenReturn(host); - when(event.getStarted()).thenReturn(Collections.<Integer>emptySet()); - when(event.getTerminated()).thenReturn(stopped); - hostListener.vmStatusChanged(event); - - // Ensure only 1 removed - assertFalse(hostListener.getMonitoredVms().containsKey(1)); - assertTrue(hostListener.getMonitoredVms().containsKey(2)); - assertEquals(monitoredVm2, hostListener.getMonitoredVms().get(2).getSecond()); - - verify(notifier).notifyVmStatusChange(eq(Status.VM_STOPPED), anyString(), (isA(Integer.class))); - - } - - @Test - public void testReusedPid() throws MonitorException { - final Set<Integer> started = new HashSet<>(); - started.add(1); - // Start VM - VmStatusChangeEvent event = mock(VmStatusChangeEvent.class); - when(event.getMonitoredHost()).thenReturn(host); - when(event.getStarted()).thenReturn(started); - when(event.getTerminated()).thenReturn(Collections.<Integer>emptySet()); - hostListener.vmStatusChanged(event); - - ArgumentCaptor<String> vmIdCaptor = ArgumentCaptor.forClass(String.class); - - // Stop VM - event = mock(VmStatusChangeEvent.class); - when(event.getMonitoredHost()).thenReturn(host); - when(event.getStarted()).thenReturn(Collections.<Integer>emptySet()); - when(event.getTerminated()).thenReturn(started); - hostListener.vmStatusChanged(event); - - // Start new VM - event = mock(VmStatusChangeEvent.class); - when(event.getMonitoredHost()).thenReturn(host); - when(event.getStarted()).thenReturn(started); - when(event.getTerminated()).thenReturn(Collections.<Integer>emptySet()); - hostListener.vmStatusChanged(event); - - verify(notifier, times(2)).notifyVmStatusChange(eq(Status.VM_STARTED), vmIdCaptor.capture(), eq(1)); - List<String> vmIds = vmIdCaptor.getAllValues(); - - assertEquals(2, vmIds.size()); - String vmId1 = vmIds.get(0); - String vmId2 = vmIds.get(1); - assertNotNull(vmId1); - assertNotNull(vmId2); - assertFalse(vmId1.equals(vmId2)); - } - - private void startVMs() throws InterruptedException, MonitorException { - final Set<Integer> started = new HashSet<>(); - started.add(1); - started.add(2); - - // Trigger a change event - VmStatusChangeEvent event = mock(VmStatusChangeEvent.class); - when(event.getMonitoredHost()).thenReturn(host); - when(event.getStarted()).thenReturn(started); - when(event.getTerminated()).thenReturn(Collections.<Integer>emptySet()); - hostListener.vmStatusChanged(event); - } - - @Test - public void testCreateVmInfo() throws MonitorException { - final String INFO_ID = "vmId"; - final int INFO_PID = 1; - final long INFO_STOPTIME = Long.MAX_VALUE; - VmInfo info = hostListener.createVmInfo(INFO_ID, INFO_PID, INFO_STOPTIME, extractor); - - assertEquals(INFO_PID, info.getVmPid()); - assertEquals(INFO_STARTTIME, info.getStartTimeStamp()); - assertEquals(INFO_STOPTIME, info.getStopTimeStamp()); - assertEquals(INFO_CMDLINE, info.getJavaCommandLine()); - assertEquals(INFO_JAVAHOME, info.getJavaHome()); - assertEquals(INFO_JAVAVER, info.getJavaVersion()); - assertEquals(INFO_MAINCLASS, info.getMainClass()); - assertEquals(INFO_VMARGS, info.getVmArguments()); - assertEquals(INFO_VMINFO, info.getVmInfo()); - assertEquals(INFO_VMNAME, info.getVmName()); - assertEquals(INFO_VMVER, info.getVmVersion()); - assertEquals(INFO_VMUSERID, info.getUid()); - assertEquals(INFO_VMUSERNAME, info.getUsername()); - } -} -
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/ProcessEnvironmentBuilderTest.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.system.internal; - -import com.redhat.thermostat.common.portability.PortableProcess; -import com.redhat.thermostat.backend.system.internal.models.ProcessEnvironmentBuilder; -import com.redhat.thermostat.shared.config.OS; - -import org.junit.Assume; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -import java.util.HashMap; -import java.util.Map; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * test windows process env builder - */ -public class ProcessEnvironmentBuilderTest { - - private PortableProcess whelp; - - private static final int FAKE_PID = 4567; - private static final String PATH_KEY = "PATH"; - private static final String FAKE_PATH = "testpath"; - - private static final Map<String,String> goodMap = new HashMap<>(); - - @Before - public void setup() { - whelp = mock(PortableProcess.class); - goodMap.put(PATH_KEY, FAKE_PATH); - when(whelp.getEnvironment(anyInt())).thenReturn(null); - when(whelp.getEnvironment(eq(FAKE_PID))).thenReturn(goodMap); - } - - @Test - public void testSimpleBuild() { - Assume.assumeTrue(OS.IS_WINDOWS); - final Map<String,String> info = new ProcessEnvironmentBuilderImpl().build(FAKE_PID); - assertNotNull(info); - } - - @Test - public void testGetInfoFromGoodPid() { - final ProcessEnvironmentBuilder ib = new ProcessEnvironmentBuilderImpl(whelp); - final Map<String,String> info = ib.build(FAKE_PID); - assertFalse(info.isEmpty()); - assertTrue(info.containsKey(PATH_KEY)); - assertEquals(FAKE_PATH, info.get(PATH_KEY)); - } - - @Test - public void testGetInfoFromBadPid() { - final ProcessEnvironmentBuilder ib = new ProcessEnvironmentBuilderImpl(whelp); - final Map<String,String> info = ib.build(FAKE_PID+1); - assertTrue(info == null || info.isEmpty()); - } -}
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/SystemBackendTest.java Thu Jun 08 20:16:03 2017 +0200 +++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/SystemBackendTest.java Fri Jun 09 16:38:44 2017 +0200 @@ -42,17 +42,12 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import org.junit.Assume; import org.junit.Before; import org.junit.Test; -import com.redhat.thermostat.agent.VmBlacklist; import com.redhat.thermostat.common.Version; -import com.redhat.thermostat.common.portability.UserNameUtil; -import com.redhat.thermostat.shared.config.OS; import com.redhat.thermostat.storage.core.WriterID; import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO; -import com.redhat.thermostat.storage.dao.VmInfoDAO; public class SystemBackendTest { @@ -62,17 +57,11 @@ @Before public void setUp() { NetworkInterfaceInfoDAO nDAO = mock(NetworkInterfaceInfoDAO.class); - VmInfoDAO vmInfoDAO = mock(VmInfoDAO.class); - Version version = mock(Version.class); when(version.getVersionNumber()).thenReturn(VERSION); - - VmStatusChangeNotifier notifier = mock(VmStatusChangeNotifier.class); - UserNameUtil util = mock(UserNameUtil.class); + WriterID id = mock(WriterID.class); - WriterID id = mock(WriterID.class); - VmBlacklist blacklist = mock(VmBlacklist.class); - b = new SystemBackend(nDAO, vmInfoDAO, version, notifier, util, id, blacklist); + b = new SystemBackend(nDAO, version, id); } @Test
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/internal/VmStatusChangeNotifierTest.java Thu Jun 08 20:16:03 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,206 +0,0 @@ -/* - * 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 - * <http://www.gnu.org/licenses/>. - * - * 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.backend.system.internal; - -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import java.util.ConcurrentModificationException; - -import org.junit.Test; -import org.osgi.framework.BundleContext; - -import com.redhat.thermostat.agent.VmStatusListener; -import com.redhat.thermostat.agent.VmStatusListener.Status; -import com.redhat.thermostat.testutils.StubBundleContext; - -public class VmStatusChangeNotifierTest { - - @Test - public void verifyWorksWithoutAnyListeners() { - final String VM_ID = "vmId"; - final int VM_PID = 2; - StubBundleContext bundleContext = new StubBundleContext(); - - VmStatusChangeNotifier notifier = new VmStatusChangeNotifier(bundleContext); - notifier.start(); - notifier.notifyVmStatusChange(Status.VM_STARTED, VM_ID, VM_PID); - - notifier.notifyVmStatusChange(Status.VM_STOPPED, VM_ID, VM_PID); - } - - @Test - public void verifyAllListenersAreNotified() { - final String VM_ID = "vmId"; - final int VM_PID = 2; - StubBundleContext bundleContext = new StubBundleContext(); - - VmStatusListener listener = mock(VmStatusListener.class); - bundleContext.registerService(VmStatusListener.class, listener, null); - - VmStatusChangeNotifier notifier = new VmStatusChangeNotifier(bundleContext); - notifier.start(); - notifier.notifyVmStatusChange(Status.VM_STARTED, VM_ID, VM_PID); - - verify(listener).vmStatusChanged(Status.VM_STARTED, VM_ID, VM_PID); - - notifier.notifyVmStatusChange(Status.VM_STOPPED, VM_ID, VM_PID); - - verify(listener).vmStatusChanged(Status.VM_STOPPED, VM_ID, VM_PID); - } - - @Test - public void verifyListenersAddedAfterVmStartRecieveVmActiveEvent() { - final String VM_ID = "vmId"; - final int VM_PID = 2; - StubBundleContext bundleContext = new StubBundleContext(); - - VmStatusChangeNotifier notifier = new VmStatusChangeNotifier(bundleContext); - notifier.start(); - notifier.notifyVmStatusChange(Status.VM_STARTED, VM_ID, VM_PID); - - VmStatusListener listener = mock(VmStatusListener.class); - bundleContext.registerService(VmStatusListener.class, listener, null); - - verify(listener).vmStatusChanged(Status.VM_ACTIVE, VM_ID, VM_PID); - - } - - /* - * Some backends might activate on activation of another backend. If both of - * them are also VmStatusListener's, a concurrent modification exception - * might be thrown. This tests verifies it's OK to do so (concurrent modification). - */ - @Test - public void canAddListenersWhileFiringEvent() throws InterruptedException { - StubBundleContext bundleContext = new StubBundleContext(); - VmStatusChangeNotifier notifier = new VmStatusChangeNotifier(bundleContext); - - // Add > 2 listeners. One of them registers another listener in vmStatusChanged() - // Thus provoking ConcurrentModificationException. - bundleContext.registerService(VmStatusListener.class, new TestVmStatusListener(bundleContext), null); - bundleContext.registerService(VmStatusListener.class, new VmStatusListener() { - - @Override - public void vmStatusChanged(Status newStatus, String vmId, - int pid) { - Debug.println("Second registered listener fired"); - } - - @Override - public int hashCode() { - return 2; // second listener to be fired - } - - }, null); - bundleContext.registerService(VmStatusListener.class, new VmStatusListener() { - - @Override - public void vmStatusChanged(Status newStatus, String vmId, - int pid) { - Debug.println("Third registered listener fired"); - } - - @Override - public int hashCode() { - return 3; - } - - }, null); - notifier.start(); - - try { - notifier.notifyVmStatusChange(Status.VM_STARTED, "foo-vmid", 333); - // this will trigger the newly added listener being invoked and counting - // down the latch. - notifier.notifyVmStatusChange(Status.VM_STARTED, "foo-other", 9999); - // pass - } catch (ConcurrentModificationException e) { - fail("Unexpected conncurrent modification exception!"); - } - } - - static class TestVmStatusListener implements VmStatusListener { - - private final BundleContext context; - - private TestVmStatusListener(BundleContext context) { - this.context = context; - } - - @Override - public void vmStatusChanged(Status newStatus, String vmId, int pid) { - Debug.println("First registered listener fired"); - context.registerService(VmStatusListener.class, new VmStatusListener() { - - @Override - public void vmStatusChanged(Status newStatus, String vmId, - int pid) { - Debug.println("Listener registered in listener (between first and second) fired"); - } - - @Override - public int hashCode() { - // Pick a large hash code since that tends to result in - // the listener being fired later on. - return 101; - } - - }, null); - } - - @Override - public int hashCode() { - // Heuristic for HashMap it tends to be picked first when iterating over - return 1; - } - - } - - static class Debug { - - static final boolean debugOn = false; // set to true for debug output - - static void println(String msg) { - if (debugOn) { - System.err.println(msg); - } - } - } -} -