Mercurial > hg > release > thermostat-2.0
changeset 2273:8197dcb387ff
Code consistency: Rename packages: '*.impl.*' => '*.internal.*'
Reviewed-by: neugens, omajid
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2016-April/018538.html
PR2138
line wrap: on
line diff
--- a/agent/cli/pom.xml Wed Apr 06 14:52:26 2016 +0200 +++ b/agent/cli/pom.xml Fri Apr 08 13:18:48 2016 +0200 @@ -122,11 +122,11 @@ <configuration> <instructions> <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor> - <Bundle-Activator>com.redhat.thermostat.agent.cli.impl.Activator</Bundle-Activator> + <Bundle-Activator>com.redhat.thermostat.agent.cli.internal.Activator</Bundle-Activator> <Bundle-SymbolicName>com.redhat.thermostat.agent.cli</Bundle-SymbolicName> <Private-Package> - com.redhat.thermostat.agent.cli.impl, - com.redhat.thermostat.agent.cli.impl.locale, + com.redhat.thermostat.agent.cli.internal, + com.redhat.thermostat.agent.cli.internal.locale, </Private-Package> <!-- Do not autogenerate uses clauses in Manifests --> <_nouses>true</_nouses>
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/Activator.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -/* - * Copyright 2012-2016 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.cli.impl; - -import java.util.Map; - -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.util.tracker.ServiceTracker; -import org.osgi.util.tracker.ServiceTrackerCustomizer; - -import com.redhat.thermostat.common.ExitStatus; -import com.redhat.thermostat.common.MultipleServiceTracker; -import com.redhat.thermostat.common.MultipleServiceTracker.Action; -import com.redhat.thermostat.common.cli.CommandRegistry; -import com.redhat.thermostat.common.cli.CommandRegistryImpl; -import com.redhat.thermostat.shared.config.SSLConfiguration; -import com.redhat.thermostat.storage.core.StorageCredentials; -import com.redhat.thermostat.storage.core.WriterID; - -public class Activator implements BundleActivator { - - private CommandRegistry reg; - private AgentApplication agentApplication; - private MultipleServiceTracker tracker; - private ServiceTracker<StorageCredentials, StorageCredentials> credsTracker; - - @Override - public void start(final BundleContext context) throws Exception { - reg = new CommandRegistryImpl(context); - - Class<?>[] deps = new Class<?>[] { - ExitStatus.class, - WriterID.class, - SSLConfiguration.class - }; - tracker = new MultipleServiceTracker(context, deps, new Action() { - - @Override - public void dependenciesAvailable(Map<String, Object> services) { - ExitStatus exitStatus = (ExitStatus) services.get(ExitStatus.class.getName()); - WriterID writerID = (WriterID) services.get(WriterID.class.getName()); - SSLConfiguration sslConf = (SSLConfiguration) services.get(SSLConfiguration.class.getName()); - agentApplication = new AgentApplication(context, exitStatus, writerID, sslConf); - reg.registerCommand("service", new ServiceCommand(context)); - reg.registerCommand("agent", agentApplication); - } - - @Override - public void dependenciesUnavailable() { - agentApplication.shutdown(ExitStatus.EXIT_SUCCESS); - reg.unregisterCommands(); - } - }); - credsTracker = new ServiceTracker<StorageCredentials, StorageCredentials>( - context, StorageCredentials.class, new ServiceTrackerCustomizer<StorageCredentials, StorageCredentials>() { - - @Override - public StorageCredentials addingService(ServiceReference<StorageCredentials> ref) { - StorageCredentials creds = context.getService(ref); - agentApplication.setStorageCredentials(creds); - return creds; - } - - @Override - public void modifiedService(ServiceReference<StorageCredentials> ref, - StorageCredentials creds) { - // nothing - } - - @Override - public void removedService(ServiceReference<StorageCredentials> ref, - StorageCredentials arg1) { - if (agentApplication != null) { - agentApplication.setStorageCredentials(null); // remove creds - } - context.ungetService(ref); - } - - }); - tracker.open(); - credsTracker.open(); - } - - @Override - public void stop(BundleContext context) throws Exception { - if (agentApplication != null) { - // Bundle may be shut down *before* deps become available and - // app is set. - agentApplication.shutdown(ExitStatus.EXIT_SUCCESS); - } - reg.unregisterCommands(); - credsTracker.close(); - tracker.close(); - } -} -
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/AgentApplication.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,393 +0,0 @@ -/* - * Copyright 2012-2016 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.cli.impl; - -import java.io.IOException; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.util.tracker.ServiceTracker; - -import sun.misc.Signal; -import sun.misc.SignalHandler; - -import com.redhat.thermostat.agent.Agent; -import com.redhat.thermostat.agent.cli.impl.locale.LocaleResources; -import com.redhat.thermostat.agent.command.ConfigurationServer; -import com.redhat.thermostat.agent.config.AgentConfigsUtils; -import com.redhat.thermostat.agent.config.AgentOptionParser; -import com.redhat.thermostat.agent.config.AgentStartupConfiguration; -import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool; -import com.redhat.thermostat.backend.BackendRegistry; -import com.redhat.thermostat.backend.BackendService; -import com.redhat.thermostat.common.ExitStatus; -import com.redhat.thermostat.common.LaunchException; -import com.redhat.thermostat.common.MultipleServiceTracker; -import com.redhat.thermostat.common.MultipleServiceTracker.Action; -import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand; -import com.redhat.thermostat.common.cli.Arguments; -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandException; -import com.redhat.thermostat.common.cli.DependencyServices; -import com.redhat.thermostat.common.tools.ApplicationState; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.shared.config.InvalidConfigurationException; -import com.redhat.thermostat.shared.config.SSLConfiguration; -import com.redhat.thermostat.shared.locale.Translate; -import com.redhat.thermostat.storage.core.Connection.ConnectionListener; -import com.redhat.thermostat.storage.core.Connection.ConnectionStatus; -import com.redhat.thermostat.storage.core.ConnectionException; -import com.redhat.thermostat.storage.core.DbService; -import com.redhat.thermostat.storage.core.DbServiceFactory; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.StorageCredentials; -import com.redhat.thermostat.storage.core.WriterID; -import com.redhat.thermostat.storage.dao.AgentInfoDAO; -import com.redhat.thermostat.storage.dao.BackendInfoDAO; - -@SuppressWarnings("restriction") -public final class AgentApplication extends AbstractStateNotifyingCommand { - - /** - * Property for turning on verbose mode. This is there so as to be able to - * run integration tests independent of log levels. - */ - private static final String VERBOSE_MODE_PROPERTY = "thermostat.agent.verbose"; - // Messages printed in verbose mode. Integration tests use this. Be careful - // when you change those! - private static final String VERBOSE_MODE_AGENT_STOPPED_MSG = "Agent stopped."; - private static final String VERBOSE_MODE_AGENT_STARTED_MSG = "Agent started."; - - private static final String SIGINT_NAME = "INT"; - private static final String SIGTERM_NAME = "TERM"; - - private static final Logger logger = LoggingUtils.getLogger(AgentApplication.class); - private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); - - private final BundleContext bundleContext; - private final ConfigurationCreator configurationCreator; - - private AgentStartupConfiguration configuration; - private AgentOptionParser parser; - private DbServiceFactory dbServiceFactory; - @SuppressWarnings("rawtypes") - private ServiceTracker configServerTracker; - private MultipleServiceTracker depTracker; - private final ExitStatus exitStatus; - private final WriterID writerId; - private final SSLConfiguration sslConf; - private final DependencyServices depServices; - private CountDownLatch shutdownLatch; - - private CustomSignalHandler handler; - - public AgentApplication(BundleContext bundleContext, ExitStatus exitStatus, WriterID writerId, SSLConfiguration sslConf) { - this(bundleContext, exitStatus, writerId, sslConf, new DependencyServices(), new ConfigurationCreator(), new DbServiceFactory()); - } - - AgentApplication(BundleContext bundleContext, ExitStatus exitStatus, WriterID writerId, SSLConfiguration sslConf, DependencyServices depServices, ConfigurationCreator configurationCreator, DbServiceFactory dbServiceFactory) { - this.bundleContext = bundleContext; - this.configurationCreator = configurationCreator; - this.dbServiceFactory = dbServiceFactory; - this.exitStatus = exitStatus; - this.writerId = writerId; - this.sslConf = sslConf; - this.depServices = depServices; - } - - private void parseArguments(Arguments args) throws InvalidConfigurationException { - parser = new AgentOptionParser(configuration, args); - parser.parse(); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - private void runAgent(CommandContext ctx) throws CommandException { - long startTime = System.currentTimeMillis(); - configuration.setStartTime(startTime); - - StorageCredentials creds = getServiceOrExit(StorageCredentials.class); - final DbService dbService = dbServiceFactory.createDbService( - configuration.getDBConnectionString(), creds, sslConf); - - shutdownLatch = new CountDownLatch(1); - - configServerTracker = new ServiceTracker(bundleContext, ConfigurationServer.class.getName(), null) { - @Override - public Object addingService(ServiceReference reference) { - final ConfigurationServer configServer = (ConfigurationServer) super.addingService(reference); - String [] host = configuration.getConfigListenAddress().split(":"); - - try { - configServer.startListening(host[0], Integer.valueOf(host[1])); - - ConnectionListener connectionListener = new ConnectionListener() { - @Override - public void changed(ConnectionStatus newStatus) { - switch (newStatus) { - case DISCONNECTED: - logger.warning("Unexpected disconnect event."); - break; - case CONNECTING: - logger.fine("Connecting to storage."); - break; - case CONNECTED: - logger.fine("Connected to storage"); - handleConnected(configServer); - break; - case FAILED_TO_CONNECT: - // ConnectionException will be thrown - break; - default: - logger.warning("Unfamiliar ConnectionStatus value: " + newStatus.toString()); - } - } - }; - - dbService.addConnectionListener(connectionListener); - logger.fine("Connecting to storage..."); - - dbService.connect(); - } catch (IOException e) { - logger.log(Level.SEVERE, e.getMessage()); - // log stack trace as info only - logger.log(Level.INFO, e.getMessage(), e); - shutdown(ExitStatus.EXIT_ERROR); - } catch (ConnectionException e) { - logger.log(Level.SEVERE, "Could not connect to storage (" + e.getMessage() + ")"); - // log stack trace as info only - logger.log(Level.INFO, "Could not connect to storage", e); - shutdown(ExitStatus.EXIT_ERROR); - } - - return configServer; - } - - @Override - public void removedService(ServiceReference reference, Object service) { - if (shutdownLatch.getCount() > 0) { - // Lost config server while still running - logger.warning("ConfigurationServer unexpectedly became unavailable"); - } - // Stop listening on command channel - ConfigurationServer server = (ConfigurationServer) service; - server.stopListening(); - super.removedService(reference, service); - } - }; - configServerTracker.open(); - - try { - // Wait for either SIGINT or SIGTERM - shutdownLatch.await(); - logger.fine("terminating agent cmd"); - } catch (InterruptedException e) { - // Ensure proper shutdown if interrupted - handler.handle(new Signal(SIGINT_NAME)); - return; - } - } - - private StorageCredentials getServiceOrExit(Class<StorageCredentials> clazz) throws CommandException { - StorageCredentials creds = depServices.getService(clazz); - if (creds == null) { - throw new CommandException(t.localize(LocaleResources.STORAGE_CREDS_UNAVAILABLE)); - } - return creds; - } - - void setStorageCredentials(StorageCredentials creds) { - if (creds == null) { - depServices.removeService(StorageCredentials.class); - } else { - depServices.addService(StorageCredentials.class, creds); - } - } - - @Override - public void run(CommandContext ctx) throws CommandException { - configuration = configurationCreator.create(); - - parseArguments(ctx.getArguments()); - if (!parser.isHelp()) { - runAgent(ctx); - } - } - - public void shutdown(int shutDownStatus) { - // Exit application - if (shutdownLatch != null) { - shutdownLatch.countDown(); - } - - if (depTracker != null) { - depTracker.close(); - } - if (configServerTracker != null) { - configServerTracker.close(); - } - this.exitStatus.setExitStatus(shutDownStatus); - if (shutDownStatus == ExitStatus.EXIT_SUCCESS) { - getNotifier().fireAction(ApplicationState.STOP); - } else { - getNotifier().fireAction(ApplicationState.FAIL); - } - } - - private class CustomSignalHandler implements SignalHandler { - - private Agent agent; - private ConfigurationServer configServer; - - public CustomSignalHandler(Agent agent, ConfigurationServer configServer) { - this.agent = agent; - this.configServer = configServer; - } - - @Override - public void handle(Signal arg0) { - configServer.stopListening(); - try { - agent.stop(); - } catch (Exception ex) { - // We don't want any exception to hold back the signal handler, otherwise - // there will be no way to actually stop Thermostat. - ex.printStackTrace(); - } - logger.fine("Agent stopped."); - // Hook for integration tests. Print a well known message to stdout - // if verbose mode is turned on via the system property. - if (Boolean.getBoolean(VERBOSE_MODE_PROPERTY)) { - System.out.println(VERBOSE_MODE_AGENT_STOPPED_MSG); - } - shutdown(ExitStatus.EXIT_SUCCESS); - } - - } - - Agent startAgent(final Storage storage, AgentInfoDAO agentInfoDAO, BackendInfoDAO backendInfoDAO, MXBeanConnectionPool pool) { - BackendRegistry backendRegistry = null; - try { - backendRegistry = new BackendRegistry(bundleContext); - - } catch (Exception e) { - logger.log(Level.SEVERE, "Could not get BackendRegistry instance.", e); - shutdown(ExitStatus.EXIT_ERROR); - // Since this would throw NPE's down the line if we continue in this - // method, let's fail right and early :) - throw new RuntimeException(e); - } - - final Agent agent = new Agent(backendRegistry, configuration, storage, agentInfoDAO, backendInfoDAO, writerId, pool); - try { - logger.fine("Starting agent."); - agent.start(); - - bundleContext.registerService(BackendService.class, new BackendService(), null); - - } catch (LaunchException le) { - logger.log(Level.SEVERE, - "Agent could not start, probably because a configured backend could not be activated.", - le); - shutdown(ExitStatus.EXIT_ERROR); - } - logger.fine("Agent started."); - // Hook for integration tests. Print a well known message to stdout - // if verbose mode is turned on via the system property. - if (Boolean.getBoolean(VERBOSE_MODE_PROPERTY)) { - System.out.println(VERBOSE_MODE_AGENT_STARTED_MSG); - } - - logger.info("Agent id: " + agent.getId()); - getNotifier().fireAction(ApplicationState.START, agent.getId()); - return agent; - } - - private void handleConnected(final ConfigurationServer configServer) { - Class<?>[] deps = new Class<?>[] { - Storage.class, - AgentInfoDAO.class, - BackendInfoDAO.class, - MXBeanConnectionPool.class - }; - depTracker = new MultipleServiceTracker(bundleContext, deps, new Action() { - - @Override - public void dependenciesAvailable(Map<String, Object> services) { - Storage storage = (Storage) services.get(Storage.class.getName()); - AgentInfoDAO agentInfoDAO = (AgentInfoDAO) services - .get(AgentInfoDAO.class.getName()); - BackendInfoDAO backendInfoDAO = (BackendInfoDAO) services - .get(BackendInfoDAO.class.getName()); - MXBeanConnectionPool pool = (MXBeanConnectionPool) services - .get(MXBeanConnectionPool.class.getName()); - - Agent agent = startAgent(storage, agentInfoDAO, backendInfoDAO, pool); - handler = new CustomSignalHandler(agent, configServer); - Signal.handle(new Signal(SIGINT_NAME), handler); - Signal.handle(new Signal(SIGTERM_NAME), handler); - } - - @Override - public void dependenciesUnavailable() { - if (shutdownLatch.getCount() > 0) { - // In the rare case we lose one of our deps, gracefully shutdown - logger.severe("Storage unexpectedly became unavailable"); - shutdown(ExitStatus.EXIT_ERROR); - } - } - - }); - depTracker.open(); - } - - static class ConfigurationCreator { - public AgentStartupConfiguration create() throws InvalidConfigurationException { - return AgentConfigsUtils.createAgentConfigs(); - } - } - - @Override - public boolean isStorageRequired() { - return false; - } - -} -
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/ServiceCommand.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,202 +0,0 @@ -/* - * Copyright 2012-2016 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.cli.impl; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Semaphore; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; - -import com.redhat.thermostat.agent.cli.impl.locale.LocaleResources; -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand; -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandException; -import com.redhat.thermostat.common.cli.Console; -import com.redhat.thermostat.common.tools.ApplicationState; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.launcher.Launcher; -import com.redhat.thermostat.shared.locale.Translate; - -/** - * Simple service that allows starting Agent and DB Backend - * in a single step. - */ -public class ServiceCommand extends AbstractStateNotifyingCommand implements ActionListener<ApplicationState> { - - private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); - private static final Logger logger = LoggingUtils.getLogger(ServiceCommand.class); - - private List<ActionListener<ApplicationState>> listeners; - private Semaphore agentBarrier = new Semaphore(0); - private BundleContext context; - private Launcher launcher; - private boolean storageFailed = false; - private boolean agentStarted = false; - private CommandContext cmdCtx; - - public ServiceCommand(BundleContext context) { - this.context = context; - listeners = new ArrayList<>(); - listeners.add(this); - } - - @Override - public void run(CommandContext ctx) throws CommandException { - cmdCtx = ctx; - ServiceReference launcherRef = context.getServiceReference(Launcher.class); - requireNonNull(launcherRef, translator.localize(LocaleResources.LAUNCHER_UNAVAILABLE)); - launcher = (Launcher) context.getService(launcherRef); - String[] storageStartArgs = new String[] { "storage", "--start" }; - launcher.run(storageStartArgs, listeners, false); - agentBarrier.acquireUninterruptibly(); - - if (storageFailed) { - storageFailed = false; - context.ungetService(launcherRef); - getNotifier().fireAction(ApplicationState.FAIL); - throw new CommandException(translator.localize(LocaleResources.SERVICE_FAILED_TO_START_DB)); - } - - String[] storageStopArgs = new String[] { "storage", "--stop" }; - launcher.run(storageStopArgs, false); - - if (agentStarted) { - getNotifier().fireAction(ApplicationState.STOP); - } - - context.ungetService(launcherRef); - cmdCtx = null; - } - - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - if (actionEvent.getSource() instanceof AbstractStateNotifyingCommand) { - AbstractStateNotifyingCommand storage = (AbstractStateNotifyingCommand) actionEvent.getSource(); - // Implementation detail: there is a single StorageCommand instance registered - // as an OSGi service. We remove ourselves as listener so that we don't get - // notified in the case that the command is invoked by some other means later. - storage.getNotifier().removeActionListener(this); - - try { - switch (actionEvent.getActionId()) { - case START: - // Payload is connection URL - Object payload = actionEvent.getPayload(); - if (payload == null || !(payload instanceof String)) { - getNotifier().fireAction(ApplicationState.FAIL); - throw new CommandException(translator.localize(LocaleResources.UNEXPECTED_RESULT_STORAGE)); - } - String dbUrl = (String) payload; - String[] agentArgs = new String[] {"agent", "-d", dbUrl}; - logger.fine("starting agent now..."); - listeners.clear(); - listeners.add(new AgentStartedListener(cmdCtx.getConsole())); - launcher.run(agentArgs, listeners, false); - break; - case FAIL: - storageFailed = true; - // Payload is exception - payload = actionEvent.getPayload(); - if (payload == null || !(payload instanceof Exception)) { - getNotifier().fireAction(ApplicationState.FAIL); - throw new CommandException(translator.localize(LocaleResources.UNEXPECTED_RESULT_STORAGE)); - } - Exception ex = (Exception) payload; - cmdCtx.getConsole().getError().println(ex.getMessage()); - logger.log(Level.WARNING, ex.getMessage(), ex); - break; - } - } catch (CommandException e) { - cmdCtx.getConsole().getError().println(e.getMessage()); - } finally { - agentBarrier.release(); - } - } - } - - @Override - public boolean isStorageRequired() { - return false; - } - - private class AgentStartedListener implements ActionListener<ApplicationState> { - - private final Console console; - - private AgentStartedListener(Console console) { - this.console = console; - } - - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - if (actionEvent.getSource() instanceof AbstractStateNotifyingCommand) { - AbstractStateNotifyingCommand agent = (AbstractStateNotifyingCommand) actionEvent.getSource(); - // Implementation detail: there is a single AgentCommand instance registered - // as an OSGi service. We remove ourselves as listener so that we don't get - // notified in the case that the command is invoked by some other means later. - agent.getNotifier().removeActionListener(this); - - ApplicationState state = actionEvent.getActionId(); - // propagate the Agent ActionEvent - switch (state) { - case START: - agentStarted = true; - logger.fine("Agent started via service. Agent ID was: " + actionEvent.getPayload()); - getNotifier().fireAction(ApplicationState.START, actionEvent.getPayload()); - break; - case FAIL: - console.getError().println(translator.localize(LocaleResources.STARTING_AGENT_FAILED).getContents()); - getNotifier().fireAction(ApplicationState.FAIL, actionEvent.getPayload()); - break; - case STOP: - getNotifier().fireAction(ApplicationState.STOP); - break; - default: - throw new AssertionError("Unexpected state " + state); - } - } - } - } - -} -
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/impl/locale/LocaleResources.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Copyright 2012-2016 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.cli.impl.locale; - -import com.redhat.thermostat.shared.locale.Translate; - -public enum LocaleResources { - - SERVICE_FAILED_TO_START_DB, - LAUNCHER_UNAVAILABLE, - UNEXPECTED_RESULT_STORAGE, - STARTING_AGENT_FAILED, - STORAGE_CREDS_UNAVAILABLE, - ; - - static final String RESOURCE_BUNDLE = "com.redhat.thermostat.agent.cli.impl.strings"; - - public static Translate<LocaleResources> createLocalizer() { - return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class); - } - -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/internal/Activator.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,132 @@ +/* + * Copyright 2012-2016 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.cli.internal; + +import java.util.Map; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; + +import com.redhat.thermostat.common.ExitStatus; +import com.redhat.thermostat.common.MultipleServiceTracker; +import com.redhat.thermostat.common.MultipleServiceTracker.Action; +import com.redhat.thermostat.common.cli.CommandRegistry; +import com.redhat.thermostat.common.cli.CommandRegistryImpl; +import com.redhat.thermostat.shared.config.SSLConfiguration; +import com.redhat.thermostat.storage.core.StorageCredentials; +import com.redhat.thermostat.storage.core.WriterID; + +public class Activator implements BundleActivator { + + private CommandRegistry reg; + private AgentApplication agentApplication; + private MultipleServiceTracker tracker; + private ServiceTracker<StorageCredentials, StorageCredentials> credsTracker; + + @Override + public void start(final BundleContext context) throws Exception { + reg = new CommandRegistryImpl(context); + + Class<?>[] deps = new Class<?>[] { + ExitStatus.class, + WriterID.class, + SSLConfiguration.class + }; + tracker = new MultipleServiceTracker(context, deps, new Action() { + + @Override + public void dependenciesAvailable(Map<String, Object> services) { + ExitStatus exitStatus = (ExitStatus) services.get(ExitStatus.class.getName()); + WriterID writerID = (WriterID) services.get(WriterID.class.getName()); + SSLConfiguration sslConf = (SSLConfiguration) services.get(SSLConfiguration.class.getName()); + agentApplication = new AgentApplication(context, exitStatus, writerID, sslConf); + reg.registerCommand("service", new ServiceCommand(context)); + reg.registerCommand("agent", agentApplication); + } + + @Override + public void dependenciesUnavailable() { + agentApplication.shutdown(ExitStatus.EXIT_SUCCESS); + reg.unregisterCommands(); + } + }); + credsTracker = new ServiceTracker<StorageCredentials, StorageCredentials>( + context, StorageCredentials.class, new ServiceTrackerCustomizer<StorageCredentials, StorageCredentials>() { + + @Override + public StorageCredentials addingService(ServiceReference<StorageCredentials> ref) { + StorageCredentials creds = context.getService(ref); + agentApplication.setStorageCredentials(creds); + return creds; + } + + @Override + public void modifiedService(ServiceReference<StorageCredentials> ref, + StorageCredentials creds) { + // nothing + } + + @Override + public void removedService(ServiceReference<StorageCredentials> ref, + StorageCredentials arg1) { + if (agentApplication != null) { + agentApplication.setStorageCredentials(null); // remove creds + } + context.ungetService(ref); + } + + }); + tracker.open(); + credsTracker.open(); + } + + @Override + public void stop(BundleContext context) throws Exception { + if (agentApplication != null) { + // Bundle may be shut down *before* deps become available and + // app is set. + agentApplication.shutdown(ExitStatus.EXIT_SUCCESS); + } + reg.unregisterCommands(); + credsTracker.close(); + tracker.close(); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/internal/AgentApplication.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,393 @@ +/* + * Copyright 2012-2016 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.cli.internal; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTracker; + +import sun.misc.Signal; +import sun.misc.SignalHandler; + +import com.redhat.thermostat.agent.Agent; +import com.redhat.thermostat.agent.cli.internal.locale.LocaleResources; +import com.redhat.thermostat.agent.command.ConfigurationServer; +import com.redhat.thermostat.agent.config.AgentConfigsUtils; +import com.redhat.thermostat.agent.config.AgentOptionParser; +import com.redhat.thermostat.agent.config.AgentStartupConfiguration; +import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool; +import com.redhat.thermostat.backend.BackendRegistry; +import com.redhat.thermostat.backend.BackendService; +import com.redhat.thermostat.common.ExitStatus; +import com.redhat.thermostat.common.LaunchException; +import com.redhat.thermostat.common.MultipleServiceTracker; +import com.redhat.thermostat.common.MultipleServiceTracker.Action; +import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand; +import com.redhat.thermostat.common.cli.Arguments; +import com.redhat.thermostat.common.cli.CommandContext; +import com.redhat.thermostat.common.cli.CommandException; +import com.redhat.thermostat.common.cli.DependencyServices; +import com.redhat.thermostat.common.tools.ApplicationState; +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.shared.config.InvalidConfigurationException; +import com.redhat.thermostat.shared.config.SSLConfiguration; +import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.storage.core.Connection.ConnectionListener; +import com.redhat.thermostat.storage.core.Connection.ConnectionStatus; +import com.redhat.thermostat.storage.core.ConnectionException; +import com.redhat.thermostat.storage.core.DbService; +import com.redhat.thermostat.storage.core.DbServiceFactory; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.core.StorageCredentials; +import com.redhat.thermostat.storage.core.WriterID; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.storage.dao.BackendInfoDAO; + +@SuppressWarnings("restriction") +public final class AgentApplication extends AbstractStateNotifyingCommand { + + /** + * Property for turning on verbose mode. This is there so as to be able to + * run integration tests independent of log levels. + */ + private static final String VERBOSE_MODE_PROPERTY = "thermostat.agent.verbose"; + // Messages printed in verbose mode. Integration tests use this. Be careful + // when you change those! + private static final String VERBOSE_MODE_AGENT_STOPPED_MSG = "Agent stopped."; + private static final String VERBOSE_MODE_AGENT_STARTED_MSG = "Agent started."; + + private static final String SIGINT_NAME = "INT"; + private static final String SIGTERM_NAME = "TERM"; + + private static final Logger logger = LoggingUtils.getLogger(AgentApplication.class); + private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); + + private final BundleContext bundleContext; + private final ConfigurationCreator configurationCreator; + + private AgentStartupConfiguration configuration; + private AgentOptionParser parser; + private DbServiceFactory dbServiceFactory; + @SuppressWarnings("rawtypes") + private ServiceTracker configServerTracker; + private MultipleServiceTracker depTracker; + private final ExitStatus exitStatus; + private final WriterID writerId; + private final SSLConfiguration sslConf; + private final DependencyServices depServices; + private CountDownLatch shutdownLatch; + + private CustomSignalHandler handler; + + public AgentApplication(BundleContext bundleContext, ExitStatus exitStatus, WriterID writerId, SSLConfiguration sslConf) { + this(bundleContext, exitStatus, writerId, sslConf, new DependencyServices(), new ConfigurationCreator(), new DbServiceFactory()); + } + + AgentApplication(BundleContext bundleContext, ExitStatus exitStatus, WriterID writerId, SSLConfiguration sslConf, DependencyServices depServices, ConfigurationCreator configurationCreator, DbServiceFactory dbServiceFactory) { + this.bundleContext = bundleContext; + this.configurationCreator = configurationCreator; + this.dbServiceFactory = dbServiceFactory; + this.exitStatus = exitStatus; + this.writerId = writerId; + this.sslConf = sslConf; + this.depServices = depServices; + } + + private void parseArguments(Arguments args) throws InvalidConfigurationException { + parser = new AgentOptionParser(configuration, args); + parser.parse(); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private void runAgent(CommandContext ctx) throws CommandException { + long startTime = System.currentTimeMillis(); + configuration.setStartTime(startTime); + + StorageCredentials creds = getServiceOrExit(StorageCredentials.class); + final DbService dbService = dbServiceFactory.createDbService( + configuration.getDBConnectionString(), creds, sslConf); + + shutdownLatch = new CountDownLatch(1); + + configServerTracker = new ServiceTracker(bundleContext, ConfigurationServer.class.getName(), null) { + @Override + public Object addingService(ServiceReference reference) { + final ConfigurationServer configServer = (ConfigurationServer) super.addingService(reference); + String [] host = configuration.getConfigListenAddress().split(":"); + + try { + configServer.startListening(host[0], Integer.valueOf(host[1])); + + ConnectionListener connectionListener = new ConnectionListener() { + @Override + public void changed(ConnectionStatus newStatus) { + switch (newStatus) { + case DISCONNECTED: + logger.warning("Unexpected disconnect event."); + break; + case CONNECTING: + logger.fine("Connecting to storage."); + break; + case CONNECTED: + logger.fine("Connected to storage"); + handleConnected(configServer); + break; + case FAILED_TO_CONNECT: + // ConnectionException will be thrown + break; + default: + logger.warning("Unfamiliar ConnectionStatus value: " + newStatus.toString()); + } + } + }; + + dbService.addConnectionListener(connectionListener); + logger.fine("Connecting to storage..."); + + dbService.connect(); + } catch (IOException e) { + logger.log(Level.SEVERE, e.getMessage()); + // log stack trace as info only + logger.log(Level.INFO, e.getMessage(), e); + shutdown(ExitStatus.EXIT_ERROR); + } catch (ConnectionException e) { + logger.log(Level.SEVERE, "Could not connect to storage (" + e.getMessage() + ")"); + // log stack trace as info only + logger.log(Level.INFO, "Could not connect to storage", e); + shutdown(ExitStatus.EXIT_ERROR); + } + + return configServer; + } + + @Override + public void removedService(ServiceReference reference, Object service) { + if (shutdownLatch.getCount() > 0) { + // Lost config server while still running + logger.warning("ConfigurationServer unexpectedly became unavailable"); + } + // Stop listening on command channel + ConfigurationServer server = (ConfigurationServer) service; + server.stopListening(); + super.removedService(reference, service); + } + }; + configServerTracker.open(); + + try { + // Wait for either SIGINT or SIGTERM + shutdownLatch.await(); + logger.fine("terminating agent cmd"); + } catch (InterruptedException e) { + // Ensure proper shutdown if interrupted + handler.handle(new Signal(SIGINT_NAME)); + return; + } + } + + private StorageCredentials getServiceOrExit(Class<StorageCredentials> clazz) throws CommandException { + StorageCredentials creds = depServices.getService(clazz); + if (creds == null) { + throw new CommandException(t.localize(LocaleResources.STORAGE_CREDS_UNAVAILABLE)); + } + return creds; + } + + void setStorageCredentials(StorageCredentials creds) { + if (creds == null) { + depServices.removeService(StorageCredentials.class); + } else { + depServices.addService(StorageCredentials.class, creds); + } + } + + @Override + public void run(CommandContext ctx) throws CommandException { + configuration = configurationCreator.create(); + + parseArguments(ctx.getArguments()); + if (!parser.isHelp()) { + runAgent(ctx); + } + } + + public void shutdown(int shutDownStatus) { + // Exit application + if (shutdownLatch != null) { + shutdownLatch.countDown(); + } + + if (depTracker != null) { + depTracker.close(); + } + if (configServerTracker != null) { + configServerTracker.close(); + } + this.exitStatus.setExitStatus(shutDownStatus); + if (shutDownStatus == ExitStatus.EXIT_SUCCESS) { + getNotifier().fireAction(ApplicationState.STOP); + } else { + getNotifier().fireAction(ApplicationState.FAIL); + } + } + + private class CustomSignalHandler implements SignalHandler { + + private Agent agent; + private ConfigurationServer configServer; + + public CustomSignalHandler(Agent agent, ConfigurationServer configServer) { + this.agent = agent; + this.configServer = configServer; + } + + @Override + public void handle(Signal arg0) { + configServer.stopListening(); + try { + agent.stop(); + } catch (Exception ex) { + // We don't want any exception to hold back the signal handler, otherwise + // there will be no way to actually stop Thermostat. + ex.printStackTrace(); + } + logger.fine("Agent stopped."); + // Hook for integration tests. Print a well known message to stdout + // if verbose mode is turned on via the system property. + if (Boolean.getBoolean(VERBOSE_MODE_PROPERTY)) { + System.out.println(VERBOSE_MODE_AGENT_STOPPED_MSG); + } + shutdown(ExitStatus.EXIT_SUCCESS); + } + + } + + Agent startAgent(final Storage storage, AgentInfoDAO agentInfoDAO, BackendInfoDAO backendInfoDAO, MXBeanConnectionPool pool) { + BackendRegistry backendRegistry = null; + try { + backendRegistry = new BackendRegistry(bundleContext); + + } catch (Exception e) { + logger.log(Level.SEVERE, "Could not get BackendRegistry instance.", e); + shutdown(ExitStatus.EXIT_ERROR); + // Since this would throw NPE's down the line if we continue in this + // method, let's fail right and early :) + throw new RuntimeException(e); + } + + final Agent agent = new Agent(backendRegistry, configuration, storage, agentInfoDAO, backendInfoDAO, writerId, pool); + try { + logger.fine("Starting agent."); + agent.start(); + + bundleContext.registerService(BackendService.class, new BackendService(), null); + + } catch (LaunchException le) { + logger.log(Level.SEVERE, + "Agent could not start, probably because a configured backend could not be activated.", + le); + shutdown(ExitStatus.EXIT_ERROR); + } + logger.fine("Agent started."); + // Hook for integration tests. Print a well known message to stdout + // if verbose mode is turned on via the system property. + if (Boolean.getBoolean(VERBOSE_MODE_PROPERTY)) { + System.out.println(VERBOSE_MODE_AGENT_STARTED_MSG); + } + + logger.info("Agent id: " + agent.getId()); + getNotifier().fireAction(ApplicationState.START, agent.getId()); + return agent; + } + + private void handleConnected(final ConfigurationServer configServer) { + Class<?>[] deps = new Class<?>[] { + Storage.class, + AgentInfoDAO.class, + BackendInfoDAO.class, + MXBeanConnectionPool.class + }; + depTracker = new MultipleServiceTracker(bundleContext, deps, new Action() { + + @Override + public void dependenciesAvailable(Map<String, Object> services) { + Storage storage = (Storage) services.get(Storage.class.getName()); + AgentInfoDAO agentInfoDAO = (AgentInfoDAO) services + .get(AgentInfoDAO.class.getName()); + BackendInfoDAO backendInfoDAO = (BackendInfoDAO) services + .get(BackendInfoDAO.class.getName()); + MXBeanConnectionPool pool = (MXBeanConnectionPool) services + .get(MXBeanConnectionPool.class.getName()); + + Agent agent = startAgent(storage, agentInfoDAO, backendInfoDAO, pool); + handler = new CustomSignalHandler(agent, configServer); + Signal.handle(new Signal(SIGINT_NAME), handler); + Signal.handle(new Signal(SIGTERM_NAME), handler); + } + + @Override + public void dependenciesUnavailable() { + if (shutdownLatch.getCount() > 0) { + // In the rare case we lose one of our deps, gracefully shutdown + logger.severe("Storage unexpectedly became unavailable"); + shutdown(ExitStatus.EXIT_ERROR); + } + } + + }); + depTracker.open(); + } + + static class ConfigurationCreator { + public AgentStartupConfiguration create() throws InvalidConfigurationException { + return AgentConfigsUtils.createAgentConfigs(); + } + } + + @Override + public boolean isStorageRequired() { + return false; + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/internal/ServiceCommand.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,202 @@ +/* + * Copyright 2012-2016 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.cli.internal; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Semaphore; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; + +import com.redhat.thermostat.agent.cli.internal.locale.LocaleResources; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand; +import com.redhat.thermostat.common.cli.CommandContext; +import com.redhat.thermostat.common.cli.CommandException; +import com.redhat.thermostat.common.cli.Console; +import com.redhat.thermostat.common.tools.ApplicationState; +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.launcher.Launcher; +import com.redhat.thermostat.shared.locale.Translate; + +/** + * Simple service that allows starting Agent and DB Backend + * in a single step. + */ +public class ServiceCommand extends AbstractStateNotifyingCommand implements ActionListener<ApplicationState> { + + private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + private static final Logger logger = LoggingUtils.getLogger(ServiceCommand.class); + + private List<ActionListener<ApplicationState>> listeners; + private Semaphore agentBarrier = new Semaphore(0); + private BundleContext context; + private Launcher launcher; + private boolean storageFailed = false; + private boolean agentStarted = false; + private CommandContext cmdCtx; + + public ServiceCommand(BundleContext context) { + this.context = context; + listeners = new ArrayList<>(); + listeners.add(this); + } + + @Override + public void run(CommandContext ctx) throws CommandException { + cmdCtx = ctx; + ServiceReference launcherRef = context.getServiceReference(Launcher.class); + requireNonNull(launcherRef, translator.localize(LocaleResources.LAUNCHER_UNAVAILABLE)); + launcher = (Launcher) context.getService(launcherRef); + String[] storageStartArgs = new String[] { "storage", "--start" }; + launcher.run(storageStartArgs, listeners, false); + agentBarrier.acquireUninterruptibly(); + + if (storageFailed) { + storageFailed = false; + context.ungetService(launcherRef); + getNotifier().fireAction(ApplicationState.FAIL); + throw new CommandException(translator.localize(LocaleResources.SERVICE_FAILED_TO_START_DB)); + } + + String[] storageStopArgs = new String[] { "storage", "--stop" }; + launcher.run(storageStopArgs, false); + + if (agentStarted) { + getNotifier().fireAction(ApplicationState.STOP); + } + + context.ungetService(launcherRef); + cmdCtx = null; + } + + @Override + public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { + if (actionEvent.getSource() instanceof AbstractStateNotifyingCommand) { + AbstractStateNotifyingCommand storage = (AbstractStateNotifyingCommand) actionEvent.getSource(); + // Implementation detail: there is a single StorageCommand instance registered + // as an OSGi service. We remove ourselves as listener so that we don't get + // notified in the case that the command is invoked by some other means later. + storage.getNotifier().removeActionListener(this); + + try { + switch (actionEvent.getActionId()) { + case START: + // Payload is connection URL + Object payload = actionEvent.getPayload(); + if (payload == null || !(payload instanceof String)) { + getNotifier().fireAction(ApplicationState.FAIL); + throw new CommandException(translator.localize(LocaleResources.UNEXPECTED_RESULT_STORAGE)); + } + String dbUrl = (String) payload; + String[] agentArgs = new String[] {"agent", "-d", dbUrl}; + logger.fine("starting agent now..."); + listeners.clear(); + listeners.add(new AgentStartedListener(cmdCtx.getConsole())); + launcher.run(agentArgs, listeners, false); + break; + case FAIL: + storageFailed = true; + // Payload is exception + payload = actionEvent.getPayload(); + if (payload == null || !(payload instanceof Exception)) { + getNotifier().fireAction(ApplicationState.FAIL); + throw new CommandException(translator.localize(LocaleResources.UNEXPECTED_RESULT_STORAGE)); + } + Exception ex = (Exception) payload; + cmdCtx.getConsole().getError().println(ex.getMessage()); + logger.log(Level.WARNING, ex.getMessage(), ex); + break; + } + } catch (CommandException e) { + cmdCtx.getConsole().getError().println(e.getMessage()); + } finally { + agentBarrier.release(); + } + } + } + + @Override + public boolean isStorageRequired() { + return false; + } + + private class AgentStartedListener implements ActionListener<ApplicationState> { + + private final Console console; + + private AgentStartedListener(Console console) { + this.console = console; + } + + @Override + public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { + if (actionEvent.getSource() instanceof AbstractStateNotifyingCommand) { + AbstractStateNotifyingCommand agent = (AbstractStateNotifyingCommand) actionEvent.getSource(); + // Implementation detail: there is a single AgentCommand instance registered + // as an OSGi service. We remove ourselves as listener so that we don't get + // notified in the case that the command is invoked by some other means later. + agent.getNotifier().removeActionListener(this); + + ApplicationState state = actionEvent.getActionId(); + // propagate the Agent ActionEvent + switch (state) { + case START: + agentStarted = true; + logger.fine("Agent started via service. Agent ID was: " + actionEvent.getPayload()); + getNotifier().fireAction(ApplicationState.START, actionEvent.getPayload()); + break; + case FAIL: + console.getError().println(translator.localize(LocaleResources.STARTING_AGENT_FAILED).getContents()); + getNotifier().fireAction(ApplicationState.FAIL, actionEvent.getPayload()); + break; + case STOP: + getNotifier().fireAction(ApplicationState.STOP); + break; + default: + throw new AssertionError("Unexpected state " + state); + } + } + } + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/internal/locale/LocaleResources.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,57 @@ +/* + * Copyright 2012-2016 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.cli.internal.locale; + +import com.redhat.thermostat.shared.locale.Translate; + +public enum LocaleResources { + + SERVICE_FAILED_TO_START_DB, + LAUNCHER_UNAVAILABLE, + UNEXPECTED_RESULT_STORAGE, + STARTING_AGENT_FAILED, + STORAGE_CREDS_UNAVAILABLE, + ; + + static final String RESOURCE_BUNDLE = "com.redhat.thermostat.agent.cli.internal.strings"; + + public static Translate<LocaleResources> createLocalizer() { + return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class); + } + +} +
--- a/agent/cli/src/main/resources/com/redhat/thermostat/agent/cli/impl/strings.properties Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -SERVICE_FAILED_TO_START_DB = Service failed to start due to error starting storage. -LAUNCHER_UNAVAILABLE = Launcher is not available -UNEXPECTED_RESULT_STORAGE = Unexpected result from storage. -STARTING_AGENT_FAILED = Thermostat agent failed to start. See logs for details. -STORAGE_CREDS_UNAVAILABLE = StorageCredentials are not available
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/main/resources/com/redhat/thermostat/agent/cli/internal/strings.properties Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,5 @@ +SERVICE_FAILED_TO_START_DB = Service failed to start due to error starting storage. +LAUNCHER_UNAVAILABLE = Launcher is not available +UNEXPECTED_RESULT_STORAGE = Unexpected result from storage. +STARTING_AGENT_FAILED = Thermostat agent failed to start. See logs for details. +STORAGE_CREDS_UNAVAILABLE = StorageCredentials are not available
--- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/ActivatorTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* - * Copyright 2012-2016 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.cli.impl; - -import static com.redhat.thermostat.testutils.Asserts.assertCommandIsRegistered; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; - -import org.junit.Test; - -import com.redhat.thermostat.common.ExitStatus; -import com.redhat.thermostat.shared.config.SSLConfiguration; -import com.redhat.thermostat.storage.core.WriterID; -import com.redhat.thermostat.testutils.StubBundleContext; - -public class ActivatorTest { - - @Test - public void verifyActivatorRegistersCommands() throws Exception { - StubBundleContext bundleContext = new StubBundleContext(); - - ExitStatus exitStatus = mock(ExitStatus.class); - WriterID writerID = mock(WriterID.class); - bundleContext.registerService(WriterID.class, writerID, null); - bundleContext.registerService(ExitStatus.class, exitStatus, null); - bundleContext.registerService(SSLConfiguration.class, mock(SSLConfiguration.class), null); - - Activator activator = new Activator(); - - assertEquals(0, bundleContext.getServiceListeners().size()); - - activator.start(bundleContext); - - assertEquals(4, bundleContext.getServiceListeners().size()); - - assertCommandIsRegistered(bundleContext, "agent", AgentApplication.class); - assertCommandIsRegistered(bundleContext, "service", ServiceCommand.class); - - activator.stop(bundleContext); - - assertEquals(0, bundleContext.getServiceListeners().size()); - assertEquals(3, bundleContext.getAllServices().size()); - } -} -
--- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/AgentApplicationTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,292 +0,0 @@ -/* - * Copyright 2012-2016 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.cli.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.powermock.api.mockito.PowerMockito.whenNew; - -import java.io.IOException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import org.osgi.framework.BundleContext; -import org.osgi.framework.InvalidSyntaxException; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import com.redhat.thermostat.agent.Agent; -import com.redhat.thermostat.agent.cli.impl.AgentApplication.ConfigurationCreator; -import com.redhat.thermostat.agent.command.ConfigurationServer; -import com.redhat.thermostat.agent.config.AgentStartupConfiguration; -import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool; -import com.redhat.thermostat.backend.BackendRegistry; -import com.redhat.thermostat.common.ExitStatus; -import com.redhat.thermostat.common.LaunchException; -import com.redhat.thermostat.common.cli.Arguments; -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandException; -import com.redhat.thermostat.common.cli.DependencyServices; -import com.redhat.thermostat.shared.config.InvalidConfigurationException; -import com.redhat.thermostat.shared.config.SSLConfiguration; -import com.redhat.thermostat.storage.core.Connection.ConnectionListener; -import com.redhat.thermostat.storage.core.Connection.ConnectionStatus; -import com.redhat.thermostat.storage.core.ConnectionException; -import com.redhat.thermostat.storage.core.DbService; -import com.redhat.thermostat.storage.core.DbServiceFactory; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.StorageCredentials; -import com.redhat.thermostat.storage.core.WriterID; -import com.redhat.thermostat.storage.dao.AgentInfoDAO; -import com.redhat.thermostat.storage.dao.BackendInfoDAO; -import com.redhat.thermostat.testutils.StubBundleContext; - -@RunWith(PowerMockRunner.class) -public class AgentApplicationTest { - - private static final String COMMAND_CHANNLE_BIND_HOST = "test"; - private static final int COMMAND_CHANNEL_BIND_PORT = 10101; - - private StubBundleContext context; - - private ConfigurationServer configServer; - private DbService dbService; - private ConfigurationCreator configCreator; - private ExitStatus exitStatus; - private DbServiceFactory dbServiceFactory; - private WriterID writerId; - - @Before - public void setUp() throws InvalidConfigurationException { - - context = new StubBundleContext(); - - AgentStartupConfiguration config = mock(AgentStartupConfiguration.class); - when(config.getDBConnectionString()).thenReturn("test string; please ignore"); - when(config.getConfigListenAddress()).thenReturn(COMMAND_CHANNLE_BIND_HOST + ":" + COMMAND_CHANNEL_BIND_PORT); - - configCreator = mock(ConfigurationCreator.class); - when(configCreator.create()).thenReturn(config); - - Storage storage = mock(Storage.class); - context.registerService(Storage.class, storage, null); - AgentInfoDAO agentInfoDAO = mock(AgentInfoDAO.class); - context.registerService(AgentInfoDAO.class.getName(), agentInfoDAO, null); - BackendInfoDAO backendInfoDAO = mock(BackendInfoDAO.class); - context.registerService(BackendInfoDAO.class.getName(), backendInfoDAO, null); - configServer = mock(ConfigurationServer.class); - context.registerService(ConfigurationServer.class.getName(), configServer, null); - dbServiceFactory = mock(DbServiceFactory.class); - dbService = mock(DbService.class); - writerId = mock(WriterID.class); - when(dbServiceFactory.createDbService(anyString(), any(StorageCredentials.class), any(SSLConfiguration.class))).thenReturn(dbService); - - exitStatus = mock(ExitStatus.class); - } - - @After - public void tearDown() { - context = null; - configServer = null; - dbService = null; - configCreator = null; - dbServiceFactory = null; - exitStatus = null; - } - - @Test - public void testAgentStartup() throws CommandException, InterruptedException { - final AgentApplication agent = new AgentApplication(context, exitStatus, writerId, mock(SSLConfiguration.class), new DependencyServices(), configCreator, dbServiceFactory); - agent.setStorageCredentials(mock(StorageCredentials.class)); - final CountDownLatch latch = new CountDownLatch(1); - final CommandException[] ce = new CommandException[1]; - final long timeoutMillis = 5000L; - - startAgentRunThread(timeoutMillis, agent, ce, latch); - - boolean ret = latch.await(timeoutMillis, TimeUnit.MILLISECONDS); - if (ce[0] != null) { - throw ce[0]; - } - if (!ret) { - fail("Timeout expired!"); - } - - } - - @Test - public void testAgentStartupConnectFailure() throws CommandException, InterruptedException { - final AgentApplication agent = new AgentApplication(context, exitStatus, writerId, mock(SSLConfiguration.class), new DependencyServices(), configCreator, dbServiceFactory); - agent.setStorageCredentials(mock(StorageCredentials.class)); - - Arguments args = mock(Arguments.class); - final CommandContext commandContext = mock(CommandContext.class); - when(commandContext.getArguments()).thenReturn(args); - - // Throw a ConnectionException when we try to connect to storage - doThrow(new ConnectionException()).when(dbService).connect(); - - agent.run(commandContext); - - // Ensure we shut down command channel server - verify(configServer).stopListening(); - } - - /* - * Having the PrepareForTest annotation on method level does not seem to - * deadlock the test, which seems to be more or less reliably reproducible - * if this annotation is at class level instead. Steps to reproduce the - * deadlock is: - * 1. Attach the PrepareForTest annotation to the class (over the test - * method) - * 2. Run the test multiple times. 5-20 times seemed sufficient for me to - * make the deadlock show up. This deadlock does not seem to happen - * otherwise (can run up to 30 times head-to-head without deadlock). - * - */ - @PrepareForTest({ AgentApplication.class }) - @SuppressWarnings("unchecked") - @Test - public void verifyBackendRegistryProblemsSetsExitStatus() throws Exception { - whenNew(BackendRegistry.class).withParameterTypes(BundleContext.class) - .withArguments(any(BundleContext.class)) - .thenThrow(InvalidSyntaxException.class); - final AgentApplication agent = new AgentApplication(context, - exitStatus, writerId, mock(SSLConfiguration.class), - mock(DependencyServices.class), configCreator, dbServiceFactory); - try { - agent.startAgent(null, null, null, null); - } catch (RuntimeException e) { - assertEquals(InvalidSyntaxException.class, e.getCause().getClass()); - } - verify(exitStatus).setExitStatus(ExitStatus.EXIT_ERROR); - } - - @PrepareForTest({ AgentApplication.class }) - @Test - public void verifyAgentLaunchExceptionSetsExitStatus() throws Exception { - whenNew(BackendRegistry.class).withParameterTypes(BundleContext.class) - .withArguments(any(BundleContext.class)) - .thenReturn(mock(BackendRegistry.class)); - Agent mockAgent = mock(Agent.class); - whenNew(Agent.class).withParameterTypes(BackendRegistry.class, - AgentStartupConfiguration.class, Storage.class, - AgentInfoDAO.class, BackendInfoDAO.class, WriterID.class, - MXBeanConnectionPool.class).withArguments( - any(BackendRegistry.class), - any(AgentStartupConfiguration.class), any(Storage.class), - any(AgentInfoDAO.class), any(BackendInfoDAO.class), any(WriterID.class), - any(MXBeanConnectionPool.class)).thenReturn(mockAgent); - doThrow(LaunchException.class).when(mockAgent).start(); - final AgentApplication agent = new AgentApplication(context, - exitStatus, writerId, mock(SSLConfiguration.class), - mock(DependencyServices.class), configCreator, dbServiceFactory); - try { - agent.startAgent(null, null, null, null); - } catch (RuntimeException e) { - fail("Should not have thrown RuntimeException"); - } - verify(exitStatus).setExitStatus(ExitStatus.EXIT_ERROR); - } - - private void startAgentRunThread(final long timoutMillis, final AgentApplication agent, final CommandException[] ce, final CountDownLatch latch) { - Arguments args = mock(Arguments.class); - final CommandContext commandContext = mock(CommandContext.class); - when(commandContext.getArguments()).thenReturn(args); - - // Immediately switch to CONNECTED state on dbService.connect - final ArgumentCaptor<ConnectionListener> listenerCaptor = ArgumentCaptor.forClass(ConnectionListener.class); - doNothing().when(dbService).addConnectionListener(listenerCaptor.capture()); - - doAnswer(new Answer<Void>() { - - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - ConnectionListener listener = listenerCaptor.getValue(); - listener.changed(ConnectionStatus.CONNECTED); - return null; - } - - }).when(dbService).connect(); - - // Run agent in a new thread so we can timeout on failure - Thread t = new Thread(new Runnable() { - - @Override - public void run() { - // Finish when config server starts listening - try { - doAnswer(new Answer<Void>() { - - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - latch.countDown(); - return null; - } - }).when(configServer).startListening(COMMAND_CHANNLE_BIND_HOST, COMMAND_CHANNEL_BIND_PORT); - } catch (IOException e1) { - fail("a mock should not throw an exception"); - } - - try { - agent.run(commandContext); - } catch (CommandException e) { - ce[0] = e; - } - } - }); - - t.start(); - } - -} -
--- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/ServiceCommandTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,412 +0,0 @@ -/* - * Copyright 2012-2016 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.cli.impl; - -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isA; -import static org.mockito.Mockito.doAnswer; -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; - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; -import java.util.Collection; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.ActionNotifier; -import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand; -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandException; -import com.redhat.thermostat.common.cli.Console; -import com.redhat.thermostat.common.tools.ApplicationState; -import com.redhat.thermostat.launcher.Launcher; -import com.redhat.thermostat.testutils.StubBundleContext; - -public class ServiceCommandTest { - - private ByteArrayOutputStream stdErrOut; - private Launcher mockLauncher; - private ServiceCommand serviceCommand; - private CommandContext mockCommandContext; - - private static ActionEvent<ApplicationState> mockActionEvent; - private static Collection<ActionListener<ApplicationState>> listeners; - - private static final String[] STORAGE_START_ARGS = { "storage", "--start" }; - private static final String[] STORAGE_STOP_ARGS = { "storage", "--stop" }; - private static final String[] AGENT_ARGS = {"agent", "-d", "Test String"}; - private static final String AGENT_ID = "Test ID"; - - @SuppressWarnings("unchecked") - @Before - public void setUp() { - StubBundleContext bundleContext = new StubBundleContext(); - mockLauncher = mock(Launcher.class); - bundleContext.registerService(Launcher.class, mockLauncher, null); - serviceCommand = new ServiceCommand(bundleContext); - - AbstractStateNotifyingCommand mockStorageCommand = mock(AbstractStateNotifyingCommand.class); - mockActionEvent = mock(ActionEvent.class); - when(mockActionEvent.getSource()).thenReturn(mockStorageCommand); - mockCommandContext = mock(CommandContext.class); - Console console = mock(Console.class); - stdErrOut = new ByteArrayOutputStream(); - PrintStream err = new PrintStream(stdErrOut); - when(console.getError()).thenReturn(err); - when(mockCommandContext.getConsole()).thenReturn(console); - - ActionNotifier<ApplicationState> mockNotifier = mock(ActionNotifier.class); - when(mockStorageCommand.getNotifier()).thenReturn(mockNotifier); - when(mockActionEvent.getPayload()).thenReturn(new String("Test String")); - } - - @After - public void tearDown() { - listeners = null; - mockLauncher = null; - serviceCommand = null; - mockActionEvent = null; - mockCommandContext = null; - } - - @SuppressWarnings("unchecked") - @Test(timeout=1000) - public void testRunOnce() throws CommandException, InterruptedException { - doAnswer(new Answer<Void>() { - public Void answer(InvocationOnMock invocation) throws Throwable { - Object[] args = invocation.getArguments(); - listeners = (Collection<ActionListener<ApplicationState>>)args[1]; - - when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START); - - for(ActionListener<ApplicationState> listener : listeners) { - listener.actionPerformed(mockActionEvent); - } - return null; - } - }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - - doAnswer(new Answer<Void>() { - public Void answer(InvocationOnMock invocation) throws Throwable { - Object[] args = invocation.getArguments(); - listeners = (Collection<ActionListener<ApplicationState>>)args[1]; - - when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START); - when(mockActionEvent.getPayload()).thenReturn(AGENT_ID); - - for(ActionListener<ApplicationState> listener : listeners) { - listener.actionPerformed(mockActionEvent); - } - return null; - } - }).when(mockLauncher).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); - - final boolean[] result = new boolean[2]; - final String[] agentIdFound = new String[1]; - serviceCommand.getNotifier().addActionListener(new ActionListener<ApplicationState>() { - @SuppressWarnings("incomplete-switch") - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - switch (actionEvent.getActionId()) { - case FAIL: - result[0] = false; - break; - case START: - result[0] = true; - agentIdFound[0] = (String) actionEvent.getPayload(); - break; - case STOP: - result[1] = true; - break; - } - } - }); - - boolean exTriggered = false; - try { - serviceCommand.run(mockCommandContext); - } catch (CommandException e) { - exTriggered = true; - } - Assert.assertFalse(exTriggered); - Assert.assertTrue("Agent expected to fire START event", result[0]); - Assert.assertTrue("Agent expected to fire STOP event", result[1]); - Assert.assertEquals("Payload does not contain AgentId matching the agent started", agentIdFound[0], AGENT_ID); - - verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - verify(mockLauncher, times(1)).run(eq(STORAGE_STOP_ARGS), anyBoolean()); - verify(mockLauncher, times(1)).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); - verify(mockActionEvent, times(2)).getActionId(); - } - - @Test(timeout=1000) - public void testStorageStartUnknownPath() throws CommandException { - doAnswer(new Answer<Void>() { - public Void answer(InvocationOnMock invocation) throws Throwable { - Object[] args = invocation.getArguments(); - listeners = (Collection<ActionListener<ApplicationState>>)args[1]; - - when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START); - // Return a null payload in order to trigger unknown path - when(mockActionEvent.getPayload()).thenReturn(null); - - for(ActionListener<ApplicationState> listener : listeners) { - listener.actionPerformed(mockActionEvent); - } - return null; - } - }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - - final boolean[] result = new boolean[1]; - serviceCommand.getNotifier().addActionListener(new ActionListener<ApplicationState>() { - @SuppressWarnings("incomplete-switch") - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - switch (actionEvent.getActionId()) { - case FAIL: - result[0] = true; - break; - case START: - result[0] = false; - break; - case STOP: - result[0] = false; - break; - } - } - }); - - boolean exTriggered = false; - try { - serviceCommand.run(mockCommandContext); - } catch (CommandException e) { - exTriggered = true; - } - Assert.assertFalse(exTriggered); - Assert.assertEquals("Unexpected result from storage.\n", stdErrOut.toString()); - Assert.assertTrue("Agent expected to fire FAIL event", result[0]); - - verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - verify(mockLauncher, times(1)).run(eq(STORAGE_STOP_ARGS), anyBoolean()); - verify(mockLauncher, never()).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); - verify(mockActionEvent, times(1)).getActionId(); - } - - @SuppressWarnings("unchecked") - @Test(timeout=1000) - public void testStorageFailStart() throws CommandException, InterruptedException { - doAnswer(new Answer<Void>() { - public Void answer(InvocationOnMock invocation) throws Throwable { - Object[] args = invocation.getArguments(); - listeners = (Collection<ActionListener<ApplicationState>>)args[1]; - - when(mockActionEvent.getActionId()).thenReturn(ApplicationState.FAIL); - when(mockActionEvent.getPayload()).thenReturn(new Exception("Test Exception")); - - for(ActionListener<ApplicationState> listener : listeners) { - listener.actionPerformed(mockActionEvent); - } - return null; - } - }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - - final boolean[] result = new boolean[1]; - serviceCommand.getNotifier().addActionListener(new ActionListener<ApplicationState>() { - @SuppressWarnings("incomplete-switch") - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - switch (actionEvent.getActionId()) { - case FAIL: - result[0] = true; - break; - case START: - result[0] = false; - break; - case STOP: - result[0] = false; - break; - } - } - }); - - boolean exTriggered = false; - try { - serviceCommand.run(mockCommandContext); - } catch (CommandException e) { - exTriggered = true; - } - Assert.assertTrue(exTriggered); - Assert.assertEquals("Test Exception\n", stdErrOut.toString()); - Assert.assertTrue("Agent expected to fire FAIL event", result[0]); - - verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - verify(mockLauncher, never()).run(eq(STORAGE_STOP_ARGS), anyBoolean()); - verify(mockLauncher, never()).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); - verify(mockActionEvent, times(1)).getActionId(); - } - - @Test(timeout=1000) - public void testStorageFailStartUnknownPath() throws CommandException { - doAnswer(new Answer<Void>() { - public Void answer(InvocationOnMock invocation) throws Throwable { - Object[] args = invocation.getArguments(); - listeners = (Collection<ActionListener<ApplicationState>>)args[1]; - - when(mockActionEvent.getActionId()).thenReturn(ApplicationState.FAIL); - // Return a null payload in order to trigger unknown path - when(mockActionEvent.getPayload()).thenReturn(null); - - for(ActionListener<ApplicationState> listener : listeners) { - listener.actionPerformed(mockActionEvent); - } - return null; - } - }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - - final boolean[] result = new boolean[1]; - serviceCommand.getNotifier().addActionListener(new ActionListener<ApplicationState>() { - @SuppressWarnings("incomplete-switch") - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - switch (actionEvent.getActionId()) { - case FAIL: - result[0] = true; - break; - case START: - result[0] = false; - break; - case STOP: - result[0] = false; - break; - } - } - }); - - boolean exTriggered = false; - try { - serviceCommand.run(mockCommandContext); - } catch (CommandException e) { - exTriggered = true; - } - Assert.assertTrue(exTriggered); - Assert.assertEquals("Unexpected result from storage.\n", stdErrOut.toString()); - Assert.assertTrue("Agent expected to fire FAIL event", result[0]); - - verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - verify(mockLauncher, never()).run(eq(STORAGE_STOP_ARGS), anyBoolean()); - verify(mockLauncher, never()).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); - verify(mockActionEvent, times(1)).getActionId(); - } - - @Test - public void testAgentStartFail() throws CommandException { - doAnswer(new Answer<Void>() { - public Void answer(InvocationOnMock invocation) throws Throwable { - Object[] args = invocation.getArguments(); - listeners = (Collection<ActionListener<ApplicationState>>)args[1]; - - when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START); - - for(ActionListener<ApplicationState> listener : listeners) { - listener.actionPerformed(mockActionEvent); - } - return null; - } - }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - doAnswer(new Answer<Void>() { - public Void answer(InvocationOnMock invocation) throws Throwable { - Object[] args = invocation.getArguments(); - listeners = (Collection<ActionListener<ApplicationState>>)args[1]; - - when(mockActionEvent.getActionId()).thenReturn(ApplicationState.FAIL); - - for(ActionListener<ApplicationState> listener : listeners) { - listener.actionPerformed(mockActionEvent); - } - return null; - } - }).when(mockLauncher).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); - - final boolean[] result = new boolean[1]; - serviceCommand.getNotifier().addActionListener(new ActionListener<ApplicationState>() { - @SuppressWarnings("incomplete-switch") - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - switch (actionEvent.getActionId()) { - case FAIL: - result[0] = true; - break; - case START: - result[0] = false; - break; - case STOP: - result[0] = false; - break; - } - } - }); - - boolean exTriggered = false; - try { - serviceCommand.run(mockCommandContext); - } catch (CommandException e) { - exTriggered = true; - } - Assert.assertFalse(exTriggered); - Assert.assertEquals("Thermostat agent failed to start. See logs for details.\n", stdErrOut.toString()); - Assert.assertTrue("Agent expected to fire FAIL event", result[0]); - - verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - verify(mockLauncher, times(1)).run(eq(STORAGE_STOP_ARGS), anyBoolean()); - verify(mockLauncher, times(1)).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); - verify(mockActionEvent, times(2)).getActionId(); - } - -} -
--- a/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/impl/locale/TranslateTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * Copyright 2012-2016 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.cli.impl.locale; - -import java.io.IOException; -import java.util.Locale; -import java.util.Properties; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class TranslateTest { - - private Locale lang; - - @Before - public void setUp() { - this.lang = Locale.getDefault(); - Locale.setDefault(Locale.US); - } - - @After - public void tearDown() { - Locale.setDefault(lang); - } - - @Test - public void testLocalizedStringsArePresent() throws IOException { - - String stringsResource = "/" + LocaleResources.RESOURCE_BUNDLE.replace(".", "/") + ".properties"; - - Properties props = new Properties(); - props.load(getClass().getResourceAsStream(stringsResource)); - - Assert.assertEquals(LocaleResources.values().length, props.values().size()); - for (LocaleResources resource : LocaleResources.values()) { - Assert.assertTrue("missing property from resource bound file: " + resource, - props.containsKey(resource.name())); - } - } -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/internal/ActivatorTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright 2012-2016 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.cli.internal; + +import static com.redhat.thermostat.testutils.Asserts.assertCommandIsRegistered; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; + +import org.junit.Test; + +import com.redhat.thermostat.common.ExitStatus; +import com.redhat.thermostat.shared.config.SSLConfiguration; +import com.redhat.thermostat.storage.core.WriterID; +import com.redhat.thermostat.testutils.StubBundleContext; + +public class ActivatorTest { + + @Test + public void verifyActivatorRegistersCommands() throws Exception { + StubBundleContext bundleContext = new StubBundleContext(); + + ExitStatus exitStatus = mock(ExitStatus.class); + WriterID writerID = mock(WriterID.class); + bundleContext.registerService(WriterID.class, writerID, null); + bundleContext.registerService(ExitStatus.class, exitStatus, null); + bundleContext.registerService(SSLConfiguration.class, mock(SSLConfiguration.class), null); + + Activator activator = new Activator(); + + assertEquals(0, bundleContext.getServiceListeners().size()); + + activator.start(bundleContext); + + assertEquals(4, bundleContext.getServiceListeners().size()); + + assertCommandIsRegistered(bundleContext, "agent", AgentApplication.class); + assertCommandIsRegistered(bundleContext, "service", ServiceCommand.class); + + activator.stop(bundleContext); + + assertEquals(0, bundleContext.getServiceListeners().size()); + assertEquals(3, bundleContext.getAllServices().size()); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/internal/AgentApplicationTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,292 @@ +/* + * Copyright 2012-2016 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.cli.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.whenNew; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.osgi.framework.BundleContext; +import org.osgi.framework.InvalidSyntaxException; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.redhat.thermostat.agent.Agent; +import com.redhat.thermostat.agent.cli.internal.AgentApplication.ConfigurationCreator; +import com.redhat.thermostat.agent.command.ConfigurationServer; +import com.redhat.thermostat.agent.config.AgentStartupConfiguration; +import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool; +import com.redhat.thermostat.backend.BackendRegistry; +import com.redhat.thermostat.common.ExitStatus; +import com.redhat.thermostat.common.LaunchException; +import com.redhat.thermostat.common.cli.Arguments; +import com.redhat.thermostat.common.cli.CommandContext; +import com.redhat.thermostat.common.cli.CommandException; +import com.redhat.thermostat.common.cli.DependencyServices; +import com.redhat.thermostat.shared.config.InvalidConfigurationException; +import com.redhat.thermostat.shared.config.SSLConfiguration; +import com.redhat.thermostat.storage.core.Connection.ConnectionListener; +import com.redhat.thermostat.storage.core.Connection.ConnectionStatus; +import com.redhat.thermostat.storage.core.ConnectionException; +import com.redhat.thermostat.storage.core.DbService; +import com.redhat.thermostat.storage.core.DbServiceFactory; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.core.StorageCredentials; +import com.redhat.thermostat.storage.core.WriterID; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.storage.dao.BackendInfoDAO; +import com.redhat.thermostat.testutils.StubBundleContext; + +@RunWith(PowerMockRunner.class) +public class AgentApplicationTest { + + private static final String COMMAND_CHANNLE_BIND_HOST = "test"; + private static final int COMMAND_CHANNEL_BIND_PORT = 10101; + + private StubBundleContext context; + + private ConfigurationServer configServer; + private DbService dbService; + private ConfigurationCreator configCreator; + private ExitStatus exitStatus; + private DbServiceFactory dbServiceFactory; + private WriterID writerId; + + @Before + public void setUp() throws InvalidConfigurationException { + + context = new StubBundleContext(); + + AgentStartupConfiguration config = mock(AgentStartupConfiguration.class); + when(config.getDBConnectionString()).thenReturn("test string; please ignore"); + when(config.getConfigListenAddress()).thenReturn(COMMAND_CHANNLE_BIND_HOST + ":" + COMMAND_CHANNEL_BIND_PORT); + + configCreator = mock(ConfigurationCreator.class); + when(configCreator.create()).thenReturn(config); + + Storage storage = mock(Storage.class); + context.registerService(Storage.class, storage, null); + AgentInfoDAO agentInfoDAO = mock(AgentInfoDAO.class); + context.registerService(AgentInfoDAO.class.getName(), agentInfoDAO, null); + BackendInfoDAO backendInfoDAO = mock(BackendInfoDAO.class); + context.registerService(BackendInfoDAO.class.getName(), backendInfoDAO, null); + configServer = mock(ConfigurationServer.class); + context.registerService(ConfigurationServer.class.getName(), configServer, null); + dbServiceFactory = mock(DbServiceFactory.class); + dbService = mock(DbService.class); + writerId = mock(WriterID.class); + when(dbServiceFactory.createDbService(anyString(), any(StorageCredentials.class), any(SSLConfiguration.class))).thenReturn(dbService); + + exitStatus = mock(ExitStatus.class); + } + + @After + public void tearDown() { + context = null; + configServer = null; + dbService = null; + configCreator = null; + dbServiceFactory = null; + exitStatus = null; + } + + @Test + public void testAgentStartup() throws CommandException, InterruptedException { + final AgentApplication agent = new AgentApplication(context, exitStatus, writerId, mock(SSLConfiguration.class), new DependencyServices(), configCreator, dbServiceFactory); + agent.setStorageCredentials(mock(StorageCredentials.class)); + final CountDownLatch latch = new CountDownLatch(1); + final CommandException[] ce = new CommandException[1]; + final long timeoutMillis = 5000L; + + startAgentRunThread(timeoutMillis, agent, ce, latch); + + boolean ret = latch.await(timeoutMillis, TimeUnit.MILLISECONDS); + if (ce[0] != null) { + throw ce[0]; + } + if (!ret) { + fail("Timeout expired!"); + } + + } + + @Test + public void testAgentStartupConnectFailure() throws CommandException, InterruptedException { + final AgentApplication agent = new AgentApplication(context, exitStatus, writerId, mock(SSLConfiguration.class), new DependencyServices(), configCreator, dbServiceFactory); + agent.setStorageCredentials(mock(StorageCredentials.class)); + + Arguments args = mock(Arguments.class); + final CommandContext commandContext = mock(CommandContext.class); + when(commandContext.getArguments()).thenReturn(args); + + // Throw a ConnectionException when we try to connect to storage + doThrow(new ConnectionException()).when(dbService).connect(); + + agent.run(commandContext); + + // Ensure we shut down command channel server + verify(configServer).stopListening(); + } + + /* + * Having the PrepareForTest annotation on method level does not seem to + * deadlock the test, which seems to be more or less reliably reproducible + * if this annotation is at class level instead. Steps to reproduce the + * deadlock is: + * 1. Attach the PrepareForTest annotation to the class (over the test + * method) + * 2. Run the test multiple times. 5-20 times seemed sufficient for me to + * make the deadlock show up. This deadlock does not seem to happen + * otherwise (can run up to 30 times head-to-head without deadlock). + * + */ + @PrepareForTest({ AgentApplication.class }) + @SuppressWarnings("unchecked") + @Test + public void verifyBackendRegistryProblemsSetsExitStatus() throws Exception { + whenNew(BackendRegistry.class).withParameterTypes(BundleContext.class) + .withArguments(any(BundleContext.class)) + .thenThrow(InvalidSyntaxException.class); + final AgentApplication agent = new AgentApplication(context, + exitStatus, writerId, mock(SSLConfiguration.class), + mock(DependencyServices.class), configCreator, dbServiceFactory); + try { + agent.startAgent(null, null, null, null); + } catch (RuntimeException e) { + assertEquals(InvalidSyntaxException.class, e.getCause().getClass()); + } + verify(exitStatus).setExitStatus(ExitStatus.EXIT_ERROR); + } + + @PrepareForTest({ AgentApplication.class }) + @Test + public void verifyAgentLaunchExceptionSetsExitStatus() throws Exception { + whenNew(BackendRegistry.class).withParameterTypes(BundleContext.class) + .withArguments(any(BundleContext.class)) + .thenReturn(mock(BackendRegistry.class)); + Agent mockAgent = mock(Agent.class); + whenNew(Agent.class).withParameterTypes(BackendRegistry.class, + AgentStartupConfiguration.class, Storage.class, + AgentInfoDAO.class, BackendInfoDAO.class, WriterID.class, + MXBeanConnectionPool.class).withArguments( + any(BackendRegistry.class), + any(AgentStartupConfiguration.class), any(Storage.class), + any(AgentInfoDAO.class), any(BackendInfoDAO.class), any(WriterID.class), + any(MXBeanConnectionPool.class)).thenReturn(mockAgent); + doThrow(LaunchException.class).when(mockAgent).start(); + final AgentApplication agent = new AgentApplication(context, + exitStatus, writerId, mock(SSLConfiguration.class), + mock(DependencyServices.class), configCreator, dbServiceFactory); + try { + agent.startAgent(null, null, null, null); + } catch (RuntimeException e) { + fail("Should not have thrown RuntimeException"); + } + verify(exitStatus).setExitStatus(ExitStatus.EXIT_ERROR); + } + + private void startAgentRunThread(final long timoutMillis, final AgentApplication agent, final CommandException[] ce, final CountDownLatch latch) { + Arguments args = mock(Arguments.class); + final CommandContext commandContext = mock(CommandContext.class); + when(commandContext.getArguments()).thenReturn(args); + + // Immediately switch to CONNECTED state on dbService.connect + final ArgumentCaptor<ConnectionListener> listenerCaptor = ArgumentCaptor.forClass(ConnectionListener.class); + doNothing().when(dbService).addConnectionListener(listenerCaptor.capture()); + + doAnswer(new Answer<Void>() { + + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + ConnectionListener listener = listenerCaptor.getValue(); + listener.changed(ConnectionStatus.CONNECTED); + return null; + } + + }).when(dbService).connect(); + + // Run agent in a new thread so we can timeout on failure + Thread t = new Thread(new Runnable() { + + @Override + public void run() { + // Finish when config server starts listening + try { + doAnswer(new Answer<Void>() { + + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + latch.countDown(); + return null; + } + }).when(configServer).startListening(COMMAND_CHANNLE_BIND_HOST, COMMAND_CHANNEL_BIND_PORT); + } catch (IOException e1) { + fail("a mock should not throw an exception"); + } + + try { + agent.run(commandContext); + } catch (CommandException e) { + ce[0] = e; + } + } + }); + + t.start(); + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/internal/ServiceCommandTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,412 @@ +/* + * Copyright 2012-2016 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.cli.internal; + +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.doAnswer; +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; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.Collection; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.ActionNotifier; +import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand; +import com.redhat.thermostat.common.cli.CommandContext; +import com.redhat.thermostat.common.cli.CommandException; +import com.redhat.thermostat.common.cli.Console; +import com.redhat.thermostat.common.tools.ApplicationState; +import com.redhat.thermostat.launcher.Launcher; +import com.redhat.thermostat.testutils.StubBundleContext; + +public class ServiceCommandTest { + + private ByteArrayOutputStream stdErrOut; + private Launcher mockLauncher; + private ServiceCommand serviceCommand; + private CommandContext mockCommandContext; + + private static ActionEvent<ApplicationState> mockActionEvent; + private static Collection<ActionListener<ApplicationState>> listeners; + + private static final String[] STORAGE_START_ARGS = { "storage", "--start" }; + private static final String[] STORAGE_STOP_ARGS = { "storage", "--stop" }; + private static final String[] AGENT_ARGS = {"agent", "-d", "Test String"}; + private static final String AGENT_ID = "Test ID"; + + @SuppressWarnings("unchecked") + @Before + public void setUp() { + StubBundleContext bundleContext = new StubBundleContext(); + mockLauncher = mock(Launcher.class); + bundleContext.registerService(Launcher.class, mockLauncher, null); + serviceCommand = new ServiceCommand(bundleContext); + + AbstractStateNotifyingCommand mockStorageCommand = mock(AbstractStateNotifyingCommand.class); + mockActionEvent = mock(ActionEvent.class); + when(mockActionEvent.getSource()).thenReturn(mockStorageCommand); + mockCommandContext = mock(CommandContext.class); + Console console = mock(Console.class); + stdErrOut = new ByteArrayOutputStream(); + PrintStream err = new PrintStream(stdErrOut); + when(console.getError()).thenReturn(err); + when(mockCommandContext.getConsole()).thenReturn(console); + + ActionNotifier<ApplicationState> mockNotifier = mock(ActionNotifier.class); + when(mockStorageCommand.getNotifier()).thenReturn(mockNotifier); + when(mockActionEvent.getPayload()).thenReturn(new String("Test String")); + } + + @After + public void tearDown() { + listeners = null; + mockLauncher = null; + serviceCommand = null; + mockActionEvent = null; + mockCommandContext = null; + } + + @SuppressWarnings("unchecked") + @Test(timeout=1000) + public void testRunOnce() throws CommandException, InterruptedException { + doAnswer(new Answer<Void>() { + public Void answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + listeners = (Collection<ActionListener<ApplicationState>>)args[1]; + + when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START); + + for(ActionListener<ApplicationState> listener : listeners) { + listener.actionPerformed(mockActionEvent); + } + return null; + } + }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); + + doAnswer(new Answer<Void>() { + public Void answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + listeners = (Collection<ActionListener<ApplicationState>>)args[1]; + + when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START); + when(mockActionEvent.getPayload()).thenReturn(AGENT_ID); + + for(ActionListener<ApplicationState> listener : listeners) { + listener.actionPerformed(mockActionEvent); + } + return null; + } + }).when(mockLauncher).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); + + final boolean[] result = new boolean[2]; + final String[] agentIdFound = new String[1]; + serviceCommand.getNotifier().addActionListener(new ActionListener<ApplicationState>() { + @SuppressWarnings("incomplete-switch") + @Override + public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { + switch (actionEvent.getActionId()) { + case FAIL: + result[0] = false; + break; + case START: + result[0] = true; + agentIdFound[0] = (String) actionEvent.getPayload(); + break; + case STOP: + result[1] = true; + break; + } + } + }); + + boolean exTriggered = false; + try { + serviceCommand.run(mockCommandContext); + } catch (CommandException e) { + exTriggered = true; + } + Assert.assertFalse(exTriggered); + Assert.assertTrue("Agent expected to fire START event", result[0]); + Assert.assertTrue("Agent expected to fire STOP event", result[1]); + Assert.assertEquals("Payload does not contain AgentId matching the agent started", agentIdFound[0], AGENT_ID); + + verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); + verify(mockLauncher, times(1)).run(eq(STORAGE_STOP_ARGS), anyBoolean()); + verify(mockLauncher, times(1)).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); + verify(mockActionEvent, times(2)).getActionId(); + } + + @Test(timeout=1000) + public void testStorageStartUnknownPath() throws CommandException { + doAnswer(new Answer<Void>() { + public Void answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + listeners = (Collection<ActionListener<ApplicationState>>)args[1]; + + when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START); + // Return a null payload in order to trigger unknown path + when(mockActionEvent.getPayload()).thenReturn(null); + + for(ActionListener<ApplicationState> listener : listeners) { + listener.actionPerformed(mockActionEvent); + } + return null; + } + }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); + + final boolean[] result = new boolean[1]; + serviceCommand.getNotifier().addActionListener(new ActionListener<ApplicationState>() { + @SuppressWarnings("incomplete-switch") + @Override + public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { + switch (actionEvent.getActionId()) { + case FAIL: + result[0] = true; + break; + case START: + result[0] = false; + break; + case STOP: + result[0] = false; + break; + } + } + }); + + boolean exTriggered = false; + try { + serviceCommand.run(mockCommandContext); + } catch (CommandException e) { + exTriggered = true; + } + Assert.assertFalse(exTriggered); + Assert.assertEquals("Unexpected result from storage.\n", stdErrOut.toString()); + Assert.assertTrue("Agent expected to fire FAIL event", result[0]); + + verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); + verify(mockLauncher, times(1)).run(eq(STORAGE_STOP_ARGS), anyBoolean()); + verify(mockLauncher, never()).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); + verify(mockActionEvent, times(1)).getActionId(); + } + + @SuppressWarnings("unchecked") + @Test(timeout=1000) + public void testStorageFailStart() throws CommandException, InterruptedException { + doAnswer(new Answer<Void>() { + public Void answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + listeners = (Collection<ActionListener<ApplicationState>>)args[1]; + + when(mockActionEvent.getActionId()).thenReturn(ApplicationState.FAIL); + when(mockActionEvent.getPayload()).thenReturn(new Exception("Test Exception")); + + for(ActionListener<ApplicationState> listener : listeners) { + listener.actionPerformed(mockActionEvent); + } + return null; + } + }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); + + final boolean[] result = new boolean[1]; + serviceCommand.getNotifier().addActionListener(new ActionListener<ApplicationState>() { + @SuppressWarnings("incomplete-switch") + @Override + public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { + switch (actionEvent.getActionId()) { + case FAIL: + result[0] = true; + break; + case START: + result[0] = false; + break; + case STOP: + result[0] = false; + break; + } + } + }); + + boolean exTriggered = false; + try { + serviceCommand.run(mockCommandContext); + } catch (CommandException e) { + exTriggered = true; + } + Assert.assertTrue(exTriggered); + Assert.assertEquals("Test Exception\n", stdErrOut.toString()); + Assert.assertTrue("Agent expected to fire FAIL event", result[0]); + + verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); + verify(mockLauncher, never()).run(eq(STORAGE_STOP_ARGS), anyBoolean()); + verify(mockLauncher, never()).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); + verify(mockActionEvent, times(1)).getActionId(); + } + + @Test(timeout=1000) + public void testStorageFailStartUnknownPath() throws CommandException { + doAnswer(new Answer<Void>() { + public Void answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + listeners = (Collection<ActionListener<ApplicationState>>)args[1]; + + when(mockActionEvent.getActionId()).thenReturn(ApplicationState.FAIL); + // Return a null payload in order to trigger unknown path + when(mockActionEvent.getPayload()).thenReturn(null); + + for(ActionListener<ApplicationState> listener : listeners) { + listener.actionPerformed(mockActionEvent); + } + return null; + } + }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); + + final boolean[] result = new boolean[1]; + serviceCommand.getNotifier().addActionListener(new ActionListener<ApplicationState>() { + @SuppressWarnings("incomplete-switch") + @Override + public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { + switch (actionEvent.getActionId()) { + case FAIL: + result[0] = true; + break; + case START: + result[0] = false; + break; + case STOP: + result[0] = false; + break; + } + } + }); + + boolean exTriggered = false; + try { + serviceCommand.run(mockCommandContext); + } catch (CommandException e) { + exTriggered = true; + } + Assert.assertTrue(exTriggered); + Assert.assertEquals("Unexpected result from storage.\n", stdErrOut.toString()); + Assert.assertTrue("Agent expected to fire FAIL event", result[0]); + + verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); + verify(mockLauncher, never()).run(eq(STORAGE_STOP_ARGS), anyBoolean()); + verify(mockLauncher, never()).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); + verify(mockActionEvent, times(1)).getActionId(); + } + + @Test + public void testAgentStartFail() throws CommandException { + doAnswer(new Answer<Void>() { + public Void answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + listeners = (Collection<ActionListener<ApplicationState>>)args[1]; + + when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START); + + for(ActionListener<ApplicationState> listener : listeners) { + listener.actionPerformed(mockActionEvent); + } + return null; + } + }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); + doAnswer(new Answer<Void>() { + public Void answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + listeners = (Collection<ActionListener<ApplicationState>>)args[1]; + + when(mockActionEvent.getActionId()).thenReturn(ApplicationState.FAIL); + + for(ActionListener<ApplicationState> listener : listeners) { + listener.actionPerformed(mockActionEvent); + } + return null; + } + }).when(mockLauncher).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); + + final boolean[] result = new boolean[1]; + serviceCommand.getNotifier().addActionListener(new ActionListener<ApplicationState>() { + @SuppressWarnings("incomplete-switch") + @Override + public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { + switch (actionEvent.getActionId()) { + case FAIL: + result[0] = true; + break; + case START: + result[0] = false; + break; + case STOP: + result[0] = false; + break; + } + } + }); + + boolean exTriggered = false; + try { + serviceCommand.run(mockCommandContext); + } catch (CommandException e) { + exTriggered = true; + } + Assert.assertFalse(exTriggered); + Assert.assertEquals("Thermostat agent failed to start. See logs for details.\n", stdErrOut.toString()); + Assert.assertTrue("Agent expected to fire FAIL event", result[0]); + + verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); + verify(mockLauncher, times(1)).run(eq(STORAGE_STOP_ARGS), anyBoolean()); + verify(mockLauncher, times(1)).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); + verify(mockActionEvent, times(2)).getActionId(); + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/cli/src/test/java/com/redhat/thermostat/agent/cli/internal/locale/TranslateTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright 2012-2016 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.cli.internal.locale; + +import java.io.IOException; +import java.util.Locale; +import java.util.Properties; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class TranslateTest { + + private Locale lang; + + @Before + public void setUp() { + this.lang = Locale.getDefault(); + Locale.setDefault(Locale.US); + } + + @After + public void tearDown() { + Locale.setDefault(lang); + } + + @Test + public void testLocalizedStringsArePresent() throws IOException { + + String stringsResource = "/" + LocaleResources.RESOURCE_BUNDLE.replace(".", "/") + ".properties"; + + Properties props = new Properties(); + props.load(getClass().getResourceAsStream(stringsResource)); + + Assert.assertEquals(LocaleResources.values().length, props.values().size()); + for (LocaleResources resource : LocaleResources.values()) { + Assert.assertTrue("missing property from resource bound file: " + resource, + props.containsKey(resource.name())); + } + } +} +
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/impl/AgentInfoPopulator.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/* - * Copyright 2012-2016 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.dev.populator.impl; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -import com.redhat.thermostat.dev.populator.config.ConfigItem; -import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords; -import com.redhat.thermostat.dev.populator.dependencies.SharedState; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.dao.AgentInfoDAO; -import com.redhat.thermostat.storage.internal.dao.AgentInfoDAOImpl; -import com.redhat.thermostat.storage.model.AgentInformation; - -public class AgentInfoPopulator extends BasePopulator { - - private final AgentInfoDAO dao; - - public AgentInfoPopulator() { - this(null); - } - - // for testing - AgentInfoPopulator(AgentInfoDAO dao) { - this.dao = dao; - } - - @Override - public SharedState addPojos(Storage storage, ConfigItem item, SharedState state) { - // Default to all alive, if unset - int aliveItems = item.getAliveItems() == ConfigItem.UNSET ? item.getNumber() : item.getAliveItems(); - List<String> processedRecords = new ArrayList<>(); - AgentInfoDAO agentInfoDao = getDao(storage); - long currentTime = System.currentTimeMillis(); - long countBefore = agentInfoDao.getCount(); - System.out.println("Populating "+ item.getNumber() + " " + item.getName() + " records"); - for (int i = 0; i < item.getNumber(); i++) { - AgentInformation agentInfo = new AgentInformation(); - String agentId = UUID.randomUUID().toString(); - processedRecords.add(agentId); - agentInfo.setAgentId(agentId); - agentInfo.setAlive(getAliveValue(aliveItems, i)); - agentInfo.setConfigListenAddress(String.format("127.0.0.1:%d", i)); - agentInfo.setStartTime(currentTime); - agentInfoDao.addAgentInformation(agentInfo); - reportProgress(item, i); - } - doWaitUntilCount(agentInfoDao, countBefore + item.getNumber()); - state.addProcessedRecords("agentId", new ProcessedRecords<>(processedRecords)); - // FIXME: Why does HostInfoDAOImpl need AgentInfoDAO? See HostInfoPopulator - state.addProperty("agent-info-dao", agentInfoDao); - return state; - } - - private boolean getAliveValue(int aliveItems, int i) { - if (i < aliveItems) { - return true; - } else { - return false; - } - } - - private AgentInfoDAO getDao(Storage storage) { - if (dao == null) { - return new AgentInfoDAOImpl(storage); - } else { - return dao; - } - } - - @Override - public String getHandledCollection() { - return AgentInfoDAO.CATEGORY.getName(); - } - -}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/impl/BasePopulator.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * Copyright 2012-2016 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.dev.populator.impl; - -import com.redhat.thermostat.dev.populator.CollectionPopulator; -import com.redhat.thermostat.dev.populator.config.ConfigItem; -import com.redhat.thermostat.storage.core.Countable; - -public abstract class BasePopulator implements CollectionPopulator { - - protected void doWaitUntilCount(Countable countable, long expectedCount) { - System.out.print("Waiting for storage items to arrive at backend..."); - long currCount = countable.getCount(); - while (currCount != expectedCount) { - try { - Thread.sleep(200); - System.out.print("."); // report some progress - } catch (InterruptedException e) { - // ignore - } - currCount = countable.getCount(); - } - System.out.println(" Done."); - } - - protected void reportProgress(ConfigItem item, int currCount) { - if (currCount > 0 && currCount % 10 == 0) { - System.out.println("Submitted " + currCount + " " + item.getName() + " records to storage."); - } - } -}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/impl/HostInfoPopulator.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +0,0 @@ -/* - * Copyright 2012-2016 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.dev.populator.impl; - -import java.util.List; -import java.util.Objects; - -import com.redhat.thermostat.dev.populator.config.ConfigItem; -import com.redhat.thermostat.dev.populator.dependencies.SharedState; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.dao.AgentInfoDAO; -import com.redhat.thermostat.storage.dao.HostInfoDAO; -import com.redhat.thermostat.storage.internal.dao.HostInfoDAOImpl; -import com.redhat.thermostat.storage.model.HostInfo; - -public class HostInfoPopulator extends BasePopulator { - - private static final String[] HOSTS_FORMAT = new String[] { - "vm-host-%06d", "prometheus-%06d", "saturn-%06d" - }; - private static final String DOMAIN_FORMAT = "domain-%06d"; - private static final String HOSTNAME_SUFFIX = "example.com"; - private static final long MB = 1024 * 1024; - private final HostInfoDAO dao; - - public HostInfoPopulator() { - this(null); - } - - HostInfoPopulator(HostInfoDAO dao) { - this.dao = dao; - } - - @Override - public SharedState addPojos(Storage storage, ConfigItem item, SharedState relState) { - // FIXME: We need the same instance of the AgentInfoDAO due to the register-category quirk. - AgentInfoDAO agentInfoDAO = Objects.requireNonNull((AgentInfoDAO)relState.getProperty("agent-info-dao")); - HostInfoDAO hostDAO = getDao(storage, agentInfoDAO); - List<String> agentIds = relState.getProcessedRecordsFor("agentId").getAll(); - int totalItems = agentIds.size(); - int currCount = 0; - long countBefore = hostDAO.getCount(); - System.out.println("Populating "+ totalItems + " " + item.getName() + " records"); - // There is a 1-to-1 correspondance between host-info and agents - for (int i = agentIds.size() - 1; i >= 0; i--) { - String agentId = agentIds.get(i); - HostInfo info = new HostInfo(); - info.setAgentId(agentId); - info.setCpuCount(getRandomInt(50 + i)); - info.setCpuModel("x86_64, data populator"); - info.setHostname(getRandomHostName(i)); - info.setOsKernel("4.2.3 data populator"); - info.setOsName("Linux Random Flavor"); - int memory = getRandomInt(500 + i); - info.setTotalMemory(memory * MB); - hostDAO.putHostInfo(info); - reportProgress(item, currCount); - currCount++; - } - doWaitUntilCount(hostDAO, countBefore + totalItems); - return relState; - } - - private String getRandomHostName(int i) { - int index = getRandomInt(HOSTS_FORMAT.length); - String hostFormat = HOSTS_FORMAT[index] + "." + DOMAIN_FORMAT + "." + HOSTNAME_SUFFIX; - return String.format(hostFormat, i, i); - } - - private int getRandomInt(int i) { - return (int)(Math.random() * i); - } - - @Override - public String getHandledCollection() { - return HostInfoDAO.hostInfoCategory.getName(); - } - - // hook for testing - private HostInfoDAO getDao(Storage storage, AgentInfoDAO agentInfoDAO) { - if (dao == null) { - return new HostInfoDAOImpl(storage, agentInfoDAO); - } else { - return dao; - } - } - -}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/impl/NetworkInfoPopulator.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,189 +0,0 @@ -/* - * Copyright 2012-2016 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.dev.populator.impl; - -import java.util.List; - -import com.redhat.thermostat.dev.populator.config.ConfigItem; -import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords; -import com.redhat.thermostat.dev.populator.dependencies.SharedState; -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.CategoryAdapter; -import com.redhat.thermostat.storage.core.Countable; -import com.redhat.thermostat.storage.core.Cursor; -import com.redhat.thermostat.storage.core.DescriptorParsingException; -import com.redhat.thermostat.storage.core.PreparedStatement; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.core.StatementExecutionException; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO; -import com.redhat.thermostat.storage.internal.dao.NetworkInterfaceInfoDAOImpl; -import com.redhat.thermostat.storage.model.AggregateCount; -import com.redhat.thermostat.storage.model.NetworkInterfaceInfo; - -public class NetworkInfoPopulator extends BasePopulator { - - static final String[] IPV4_FORMATS = new String[] { - "192.168.0.%d", "10.33.4.%d", "89.15.93.%d" - }; - static final String[] IPV6_FORMATS = new String[] { - "e8:b1:fc:d2:e3:%s%%%s", "fe80::56ee:75ff:fe35:%s%%%s", - "0:0:0:0:0:0:0:%s%%%s" - }; - private final String[] IFACE_NAMES = new String[] { - "lo", "enp0s25", "tun0", "virbr0", "wlp4s0" - }; - private static int IPv6Mod = Integer.parseInt("ffff", 16); - private static int IPv4Mod = 255; - - private final NetworkInterfaceDAOCountable dao; - - public NetworkInfoPopulator() { - this(null); - } - - NetworkInfoPopulator(NetworkInterfaceDAOCountable dao) { - this.dao = dao; - } - - @Override - public SharedState addPojos(Storage storage, ConfigItem item, SharedState relState) { - ProcessedRecords<String> procAgents = relState.getProcessedRecordsFor("agentId"); - NetworkInterfaceDAOCountable dao = getDao(storage); - List<String> allAgents = procAgents.getAll(); - long countBefore = dao.getCount(); - int totalItems = item.getNumber() * allAgents.size(); - // populate network info records per agentID - System.out.println("Populating "+ totalItems + " " + item.getName() + " records"); - int currVal = 0; - for (String agentId: allAgents) { - for (int i = 0; i < item.getNumber(); i++) { - NetworkInterfaceInfo info = new NetworkInterfaceInfo(); - info.setAgentId(agentId); - String name = getRandomInterfaceName(i); - info.setInterfaceName(name); - info.setIp6Addr(getRandomIpv6Address(i, name)); - info.setIp4Addr(getRandomIpv4Addrees(i)); - dao.putNetworkInterfaceInfo(info); - reportProgress(item, currVal); - currVal++; - } - } - doWaitUntilCount(dao, countBefore + totalItems); - return relState; - } - - private String getRandomIpv4Addrees(int i) { - int idx = getRandomInt(IPV4_FORMATS.length); - return String.format(IPV4_FORMATS[idx], getIpv4Octet(i)); - } - - private int getRandomInt(int upperBound) { - return (int)(Math.random() * upperBound); - } - - private String getRandomIpv6Address(int i, String name) { - int idx = getRandomInt(IPV6_FORMATS.length); - return String.format(IPV6_FORMATS[idx], getIpv6Hextet(i), name); - } - - // package-private for testing - String getIpv6Hextet(int i) { - int remainder = i % IPv6Mod; - if (remainder == 0) { - // 0 isn't really an IP, make it 1 instead. - remainder = 1; - } - return Integer.toHexString(remainder); - } - - // package-private for testing - int getIpv4Octet(int i) { - int remainder = i % IPv4Mod; - if (remainder == 0) { - // 0 is network address, switch to IP - remainder = 1; - } - return remainder; - } - - private String getRandomInterfaceName(int i) { - int idx = getRandomInt(IFACE_NAMES.length); - return IFACE_NAMES[idx] + i; - } - - private NetworkInterfaceDAOCountable getDao(Storage storage) { - if (this.dao == null) { - return new NetworkInterfaceDAOCountable(storage); - } - return dao; - } - - @Override - public String getHandledCollection() { - return NetworkInterfaceInfoDAO.networkInfoCategory.getName(); - } - - static class NetworkInterfaceDAOCountable extends NetworkInterfaceInfoDAOImpl implements Countable { - - private final Category<AggregateCount> aggregateCategory; - private final Storage storage; - - NetworkInterfaceDAOCountable(Storage storage) { - super(storage); - CategoryAdapter<NetworkInterfaceInfo, AggregateCount> adapter = new CategoryAdapter<>(networkInfoCategory); - aggregateCategory = adapter.getAdapted(AggregateCount.class); - storage.registerCategory(aggregateCategory); - this.storage = storage; - } - - @Override - public long getCount() { - String descriptor = "QUERY-COUNT " + networkInfoCategory.getName(); - try { - PreparedStatement<AggregateCount> stmt = storage.prepareStatement(new StatementDescriptor<>(aggregateCategory, descriptor)); - Cursor<AggregateCount> cursor = stmt.executeQuery(); - AggregateCount count = cursor.next(); - return count.getCount(); - } catch (DescriptorParsingException | StatementExecutionException e) { - throw new RuntimeException(e); - } - } - - } - -}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/impl/ThreadPopulator.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,282 +0,0 @@ -/* - * Copyright 2012-2016 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.dev.populator.impl; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -import com.redhat.thermostat.common.Pair; -import com.redhat.thermostat.dev.populator.config.ConfigItem; -import com.redhat.thermostat.dev.populator.dependencies.SharedState; -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.CategoryAdapter; -import com.redhat.thermostat.storage.core.Countable; -import com.redhat.thermostat.storage.core.Cursor; -import com.redhat.thermostat.storage.core.DescriptorParsingException; -import com.redhat.thermostat.storage.core.PreparedStatement; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.core.StatementExecutionException; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.model.AggregateCount; -import com.redhat.thermostat.thread.dao.ThreadDao; -import com.redhat.thermostat.thread.dao.impl.ThreadDaoImpl; -import com.redhat.thermostat.thread.model.ThreadHarvestingStatus; -import com.redhat.thermostat.thread.model.ThreadSession; -import com.redhat.thermostat.thread.model.ThreadState; -import com.redhat.thermostat.thread.model.ThreadSummary; -import com.redhat.thermostat.thread.model.VmDeadLockData; - -public class ThreadPopulator extends BasePopulator { - - /** - * Package-private and static for testing. - */ - static final int NUM_SAMPLES = 10; - - public final String SESSION = "session"; - private final int NUM_THREADS = 3; - private final long SEED = 5; - Random generator = new Random(SEED); - private static final String[] THREAD_NAMES = new String[] { - "Spencer", "Sheldon", "Alice", "Bob", "Julie", "Phoebe", "Alpha", "Beta", "Gamma", - "Theta", "Zeta", - }; - static final String DEADLOCK_DESC_FORMAT = "" + - "\"%s\" Id=%d WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7 owned by \"%s\" Id=%d\n" + - "\tat sun.misc.Unsafe.park(Native Method)\n" + - "\t- waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7\n" + - "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + - "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" + - "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" + - "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" + - "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" + - "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" + - "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" + - "\t...\n\n" + - "\tNumber of locked synchronizers = 1\n" + - "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2\n" + - "\n\n" + - "\"%s\" Id=%d WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e owned by \"%s\" Id=%d\n" + - "\tat sun.misc.Unsafe.park(Native Method)\n" + - "\t- waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e\n" + - "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + - "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" + - "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" + - "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" + - "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" + - "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" + - "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" + - "\t...\n\n" + - "\tNumber of locked synchronizers = 1\n" + - "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7\n" + - "\n\n" + - "\"%s\" Id=%d WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2 owned by \"%s\" Id=%d\n" + - "\tat sun.misc.Unsafe.park(Native Method)\n" + - "\t- waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2\n" + - "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + - "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" + - "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" + - "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" + - "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" + - "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" + - "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" + - "\t...\n\n" + - "\tNumber of locked synchronizers = 1\n" + - "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e\n\n\n"; - - - private ThreadDaoCountable dao; - - public ThreadPopulator() { - this(null); - } - - ThreadPopulator(ThreadDaoCountable dao) { - this.dao = dao; - } - - // Testing hook - private void createDao(Storage storage) { - if (dao == null) { - dao = new ThreadDaoCountable(storage); - } - } - - @Override - public SharedState addPojos(Storage storage, ConfigItem item, SharedState relState) { - createDao(storage); - // creates records per agent *and* vm - List<String> agentIds = relState.getProcessedRecordsFor("agentId").getAll(); - List<String> vmIds = relState.getProcessedRecordsFor("vmId").getAll(); - int perVmNumber = item.getNumber(); - int totalCount = perVmNumber * agentIds.size() * vmIds.size(); - int currCount = 0; - long countBefore = dao.getCount(); - System.out.println("Populating "+ totalCount + " " + item.getName() + " records"); - long currTime = System.currentTimeMillis(); - for (String agentId: agentIds) { - for (String vmId: vmIds) { - for (int i = 0; i < perVmNumber; i++) { - ThreadSummary summary = new ThreadSummary(); - summary.setAgentId(agentId); - summary.setVmId(vmId); - int liveThreads = generator.nextInt(NUM_THREADS); - summary.setCurrentLiveThreads(liveThreads); - int daemonThreads = NUM_THREADS - liveThreads; - summary.setCurrentDaemonThreads(daemonThreads); - long timeStamp = currTime + i * 1000; - summary.setTimeStamp(timeStamp); - dao.saveSummary(summary); - - ThreadSession session = new ThreadSession(); - session.setSession(SESSION); - session.setTimeStamp(timeStamp); - session.setAgentId(agentId); - session.setVmId(vmId); - dao.saveSession(session); - - final Thread.State[] states = Thread.State.values(); - String state = states[generator.nextInt(states.length)].toString(); - String name = THREAD_NAMES[generator.nextInt(THREAD_NAMES.length)]; - - for(int j = 0; j < NUM_SAMPLES; j++) { - ThreadState threadState = new ThreadState(); - threadState.setTimeStamp(currTime + j * 1000); - threadState.setVmId(vmId); - threadState.setAgentId(agentId); - threadState.setState(state); - threadState.setId(i); - threadState.setName(name); - threadState.setSession(SESSION); - dao.addThreadState(threadState); - } - - ThreadHarvestingStatus status = new ThreadHarvestingStatus(agentId); - status.setVmId(vmId); - status.setTimeStamp(timeStamp); - status.setHarvesting(generator.nextBoolean()); - dao.saveHarvestingStatus(status); - - VmDeadLockData data = new VmDeadLockData(); - data.setAgentId(agentId); - data.setVmId(vmId); - data.setTimeStamp(currTime + i * 10); - data.setDeadLockDescription(getDeadlockedDescription(currCount)); - dao.saveDeadLockStatus(data); - currCount++; - reportProgress(item, currCount); - } - } - } - doWaitUntilCount(dao, countBefore + totalCount); - return relState; - } - - private String getDeadlockedDescription(int currCount) { - return String.format(DEADLOCK_DESC_FORMAT, getFormatStringArgs(currCount)); - } - - Object[] getFormatStringArgs(int currCount) { - List<Pair<String, Integer>> nameIdMapping = new ArrayList<>(); - int[] randomIds = getIdValues(currCount, NUM_THREADS); - int randomEntry = getRandomInt(THREAD_NAMES.length); - for (int i = 0, idx; i < NUM_THREADS; i++) { - idx = (randomEntry + i) % THREAD_NAMES.length; - String name = THREAD_NAMES[idx]; - int tid = randomIds[i]; - nameIdMapping.add(new Pair<>(name, tid)); - } - Object[] formatArgs = new Object[NUM_THREADS * 2 * 2]; - formatArgs[0] = nameIdMapping.get(0).getFirst(); - formatArgs[1] = nameIdMapping.get(0).getSecond(); - for (int i = 2, j = 1; i < formatArgs.length - 2; i+= 4, j++) { - formatArgs[i] = nameIdMapping.get(j).getFirst(); - formatArgs[i + 1] = nameIdMapping.get(j).getSecond(); - formatArgs[i + 2] = nameIdMapping.get(j).getFirst(); - formatArgs[i + 3] = nameIdMapping.get(j).getSecond(); - } - formatArgs[formatArgs.length - 2] = nameIdMapping.get(0).getFirst(); - formatArgs[formatArgs.length - 1] = nameIdMapping.get(0).getSecond(); - return formatArgs; - } - - private int getRandomInt(int len) { - return (int)(Math.random() * len); - } - - private int[] getIdValues(int currCount, int length) { - int[] values = new int[length]; - for (int i = 0; i < values.length; i++) { - values[i] = currCount + i; - } - return values; - } - - @Override - public String getHandledCollection() { - return ThreadDao.THREAD_HARVESTING_STATUS.getName(); - } - - static class ThreadDaoCountable extends ThreadDaoImpl implements Countable { - - private final Category<AggregateCount> aggregateCategory; - private final Storage storage; - - public ThreadDaoCountable(Storage storage) { - super(storage); - CategoryAdapter<VmDeadLockData, AggregateCount> adapter = new CategoryAdapter<>(DEADLOCK_INFO); - aggregateCategory = adapter.getAdapted(AggregateCount.class); - storage.registerCategory(aggregateCategory); - this.storage = storage; - } - - @Override - public long getCount() { - String descriptor = "QUERY-COUNT " + DEADLOCK_INFO.getName(); - try { - PreparedStatement<AggregateCount> stmt = storage.prepareStatement(new StatementDescriptor<>(aggregateCategory, descriptor)); - Cursor<AggregateCount> cursor = stmt.executeQuery(); - AggregateCount count = cursor.next(); - return count.getCount(); - } catch (DescriptorParsingException | StatementExecutionException e) { - throw new RuntimeException(e); - } - } - - } -}
--- a/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/impl/VmInfoPopulator.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -/* - * Copyright 2012-2016 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.dev.populator.impl; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import com.redhat.thermostat.dev.populator.config.ConfigItem; -import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords; -import com.redhat.thermostat.dev.populator.dependencies.SharedState; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.dao.VmInfoDAO; -import com.redhat.thermostat.storage.internal.dao.VmInfoDAOImpl; -import com.redhat.thermostat.storage.model.VmInfo; - -public class VmInfoPopulator extends BasePopulator { - - private final VmInfoDAO dao; - - public VmInfoPopulator() { - this(null); - } - - VmInfoPopulator(VmInfoDAO dao) { - this.dao = dao; - } - - @Override - public SharedState addPojos(Storage storage, ConfigItem item, SharedState relState) { - // Default to all alive, if unset - int aliveItems = item.getAliveItems() == ConfigItem.UNSET ? item.getNumber() : item.getAliveItems(); - ProcessedRecords<String> procAgents = relState.getProcessedRecordsFor("agentId"); - List<String> vmIds = new ArrayList<>(); - VmInfoDAO dao = getDao(storage); - List<String> allAgents = procAgents.getAll(); - long countBefore = dao.getCount(); - int totalItems = item.getNumber() * allAgents.size(); - // populate VM records per agentID - System.out.println("Populating "+ totalItems + " " + item.getName() + " records"); - int currVal = 0; - for (String agentId: allAgents) { - for (int i = 0; i < item.getNumber(); i++) { - VmInfo info = new VmInfo(); - info.setAgentId(agentId); - info.setJavaCommandLine("java DataPopulatorProducedVM --vm " + i + " --version"); - info.setJavaHome("/opt/foo/bar/java-1.8.0-openjdk/jre"); - info.setJavaVersion("1.8.0"); - info.setMainClass("com.redhat.thermostat.TestDataPopulator"); - info.setLoadedNativeLibraries(new String[] { "glibc.so", "something.so" }); - info.setProperties(getFakeJavaProperties(i, agentId)); - StartStopTimeStamp ts = getFakeStartStopTimeStamp(i, aliveItems); - info.setStartTimeStamp(ts.startTS); - info.setStopTimeStamp(ts.stopTS); - info.setUsername("vm-user-" + i); - info.setUid(i); - info.setVmArguments("-XX:+UseG1Gc"); - String vmId = UUID.randomUUID().toString(); - info.setVmId(vmId); - vmIds.add(vmId); - info.setVmInfo("OpenJDK 8"); - info.setVmPid(34 + i); - info.setVmVersion("hs 25"); - info.setVmName("Hotspot"); - dao.putVmInfo(info); - reportProgress(item, currVal); - currVal++; - } - } - doWaitUntilCount(dao, countBefore + totalItems); - relState.addProcessedRecords("vmId", new ProcessedRecords<>(vmIds)); - return relState; - } - - private StartStopTimeStamp getFakeStartStopTimeStamp(int num, int aliveItems) { - long currTime = System.currentTimeMillis(); - if (num < aliveItems) { - // create alive timestamp pair - long startTs = Long.MAX_VALUE; - long stopTs = currTime; - return new StartStopTimeStamp(startTs, stopTs); - } - // create dead timestamp pair - return new StartStopTimeStamp(currTime - (1000 + num), currTime - (500 + num)); - } - - private Map<String, String> getFakeJavaProperties(int i, String agentId) { - Map<String, String> props = new HashMap<String, String>(); - props.put("foo", "bar"); - props.put("vm#", Integer.toString(i)); - props.put("agentId", agentId); - return props; - } - - // hook for testing - private VmInfoDAO getDao(Storage storage) { - if (dao == null) { - return new VmInfoDAOImpl(storage); - } else { - return dao; - } - } - - @Override - public String getHandledCollection() { - return VmInfoDAO.vmInfoCategory.getName(); - } - - private static class StartStopTimeStamp { - private final long startTS; - private final long stopTS; - - private StartStopTimeStamp(long start, long stop) { - this.startTS = start; - this.stopTS = stop; - } - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/internal/AgentInfoPopulator.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,112 @@ +/* + * Copyright 2012-2016 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.dev.populator.internal; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import com.redhat.thermostat.dev.populator.config.ConfigItem; +import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords; +import com.redhat.thermostat.dev.populator.dependencies.SharedState; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.storage.internal.dao.AgentInfoDAOImpl; +import com.redhat.thermostat.storage.model.AgentInformation; + +public class AgentInfoPopulator extends BasePopulator { + + private final AgentInfoDAO dao; + + public AgentInfoPopulator() { + this(null); + } + + // for testing + AgentInfoPopulator(AgentInfoDAO dao) { + this.dao = dao; + } + + @Override + public SharedState addPojos(Storage storage, ConfigItem item, SharedState state) { + // Default to all alive, if unset + int aliveItems = item.getAliveItems() == ConfigItem.UNSET ? item.getNumber() : item.getAliveItems(); + List<String> processedRecords = new ArrayList<>(); + AgentInfoDAO agentInfoDao = getDao(storage); + long currentTime = System.currentTimeMillis(); + long countBefore = agentInfoDao.getCount(); + System.out.println("Populating "+ item.getNumber() + " " + item.getName() + " records"); + for (int i = 0; i < item.getNumber(); i++) { + AgentInformation agentInfo = new AgentInformation(); + String agentId = UUID.randomUUID().toString(); + processedRecords.add(agentId); + agentInfo.setAgentId(agentId); + agentInfo.setAlive(getAliveValue(aliveItems, i)); + agentInfo.setConfigListenAddress(String.format("127.0.0.1:%d", i)); + agentInfo.setStartTime(currentTime); + agentInfoDao.addAgentInformation(agentInfo); + reportProgress(item, i); + } + doWaitUntilCount(agentInfoDao, countBefore + item.getNumber()); + state.addProcessedRecords("agentId", new ProcessedRecords<>(processedRecords)); + // FIXME: Why does HostInfoDAOImpl need AgentInfoDAO? See HostInfoPopulator + state.addProperty("agent-info-dao", agentInfoDao); + return state; + } + + private boolean getAliveValue(int aliveItems, int i) { + if (i < aliveItems) { + return true; + } else { + return false; + } + } + + private AgentInfoDAO getDao(Storage storage) { + if (dao == null) { + return new AgentInfoDAOImpl(storage); + } else { + return dao; + } + } + + @Override + public String getHandledCollection() { + return AgentInfoDAO.CATEGORY.getName(); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/internal/BasePopulator.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright 2012-2016 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.dev.populator.internal; + +import com.redhat.thermostat.dev.populator.CollectionPopulator; +import com.redhat.thermostat.dev.populator.config.ConfigItem; +import com.redhat.thermostat.storage.core.Countable; + +public abstract class BasePopulator implements CollectionPopulator { + + protected void doWaitUntilCount(Countable countable, long expectedCount) { + System.out.print("Waiting for storage items to arrive at backend..."); + long currCount = countable.getCount(); + while (currCount != expectedCount) { + try { + Thread.sleep(200); + System.out.print("."); // report some progress + } catch (InterruptedException e) { + // ignore + } + currCount = countable.getCount(); + } + System.out.println(" Done."); + } + + protected void reportProgress(ConfigItem item, int currCount) { + if (currCount > 0 && currCount % 10 == 0) { + System.out.println("Submitted " + currCount + " " + item.getName() + " records to storage."); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/internal/HostInfoPopulator.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,122 @@ +/* + * Copyright 2012-2016 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.dev.populator.internal; + +import java.util.List; +import java.util.Objects; + +import com.redhat.thermostat.dev.populator.config.ConfigItem; +import com.redhat.thermostat.dev.populator.dependencies.SharedState; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.storage.dao.HostInfoDAO; +import com.redhat.thermostat.storage.internal.dao.HostInfoDAOImpl; +import com.redhat.thermostat.storage.model.HostInfo; + +public class HostInfoPopulator extends BasePopulator { + + private static final String[] HOSTS_FORMAT = new String[] { + "vm-host-%06d", "prometheus-%06d", "saturn-%06d" + }; + private static final String DOMAIN_FORMAT = "domain-%06d"; + private static final String HOSTNAME_SUFFIX = "example.com"; + private static final long MB = 1024 * 1024; + private final HostInfoDAO dao; + + public HostInfoPopulator() { + this(null); + } + + HostInfoPopulator(HostInfoDAO dao) { + this.dao = dao; + } + + @Override + public SharedState addPojos(Storage storage, ConfigItem item, SharedState relState) { + // FIXME: We need the same instance of the AgentInfoDAO due to the register-category quirk. + AgentInfoDAO agentInfoDAO = Objects.requireNonNull((AgentInfoDAO)relState.getProperty("agent-info-dao")); + HostInfoDAO hostDAO = getDao(storage, agentInfoDAO); + List<String> agentIds = relState.getProcessedRecordsFor("agentId").getAll(); + int totalItems = agentIds.size(); + int currCount = 0; + long countBefore = hostDAO.getCount(); + System.out.println("Populating "+ totalItems + " " + item.getName() + " records"); + // There is a 1-to-1 correspondance between host-info and agents + for (int i = agentIds.size() - 1; i >= 0; i--) { + String agentId = agentIds.get(i); + HostInfo info = new HostInfo(); + info.setAgentId(agentId); + info.setCpuCount(getRandomInt(50 + i)); + info.setCpuModel("x86_64, data populator"); + info.setHostname(getRandomHostName(i)); + info.setOsKernel("4.2.3 data populator"); + info.setOsName("Linux Random Flavor"); + int memory = getRandomInt(500 + i); + info.setTotalMemory(memory * MB); + hostDAO.putHostInfo(info); + reportProgress(item, currCount); + currCount++; + } + doWaitUntilCount(hostDAO, countBefore + totalItems); + return relState; + } + + private String getRandomHostName(int i) { + int index = getRandomInt(HOSTS_FORMAT.length); + String hostFormat = HOSTS_FORMAT[index] + "." + DOMAIN_FORMAT + "." + HOSTNAME_SUFFIX; + return String.format(hostFormat, i, i); + } + + private int getRandomInt(int i) { + return (int)(Math.random() * i); + } + + @Override + public String getHandledCollection() { + return HostInfoDAO.hostInfoCategory.getName(); + } + + // hook for testing + private HostInfoDAO getDao(Storage storage, AgentInfoDAO agentInfoDAO) { + if (dao == null) { + return new HostInfoDAOImpl(storage, agentInfoDAO); + } else { + return dao; + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/internal/NetworkInfoPopulator.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,189 @@ +/* + * Copyright 2012-2016 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.dev.populator.internal; + +import java.util.List; + +import com.redhat.thermostat.dev.populator.config.ConfigItem; +import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords; +import com.redhat.thermostat.dev.populator.dependencies.SharedState; +import com.redhat.thermostat.storage.core.Category; +import com.redhat.thermostat.storage.core.CategoryAdapter; +import com.redhat.thermostat.storage.core.Countable; +import com.redhat.thermostat.storage.core.Cursor; +import com.redhat.thermostat.storage.core.DescriptorParsingException; +import com.redhat.thermostat.storage.core.PreparedStatement; +import com.redhat.thermostat.storage.core.StatementDescriptor; +import com.redhat.thermostat.storage.core.StatementExecutionException; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO; +import com.redhat.thermostat.storage.internal.dao.NetworkInterfaceInfoDAOImpl; +import com.redhat.thermostat.storage.model.AggregateCount; +import com.redhat.thermostat.storage.model.NetworkInterfaceInfo; + +public class NetworkInfoPopulator extends BasePopulator { + + static final String[] IPV4_FORMATS = new String[] { + "192.168.0.%d", "10.33.4.%d", "89.15.93.%d" + }; + static final String[] IPV6_FORMATS = new String[] { + "e8:b1:fc:d2:e3:%s%%%s", "fe80::56ee:75ff:fe35:%s%%%s", + "0:0:0:0:0:0:0:%s%%%s" + }; + private final String[] IFACE_NAMES = new String[] { + "lo", "enp0s25", "tun0", "virbr0", "wlp4s0" + }; + private static int IPv6Mod = Integer.parseInt("ffff", 16); + private static int IPv4Mod = 255; + + private final NetworkInterfaceDAOCountable dao; + + public NetworkInfoPopulator() { + this(null); + } + + NetworkInfoPopulator(NetworkInterfaceDAOCountable dao) { + this.dao = dao; + } + + @Override + public SharedState addPojos(Storage storage, ConfigItem item, SharedState relState) { + ProcessedRecords<String> procAgents = relState.getProcessedRecordsFor("agentId"); + NetworkInterfaceDAOCountable dao = getDao(storage); + List<String> allAgents = procAgents.getAll(); + long countBefore = dao.getCount(); + int totalItems = item.getNumber() * allAgents.size(); + // populate network info records per agentID + System.out.println("Populating "+ totalItems + " " + item.getName() + " records"); + int currVal = 0; + for (String agentId: allAgents) { + for (int i = 0; i < item.getNumber(); i++) { + NetworkInterfaceInfo info = new NetworkInterfaceInfo(); + info.setAgentId(agentId); + String name = getRandomInterfaceName(i); + info.setInterfaceName(name); + info.setIp6Addr(getRandomIpv6Address(i, name)); + info.setIp4Addr(getRandomIpv4Addrees(i)); + dao.putNetworkInterfaceInfo(info); + reportProgress(item, currVal); + currVal++; + } + } + doWaitUntilCount(dao, countBefore + totalItems); + return relState; + } + + private String getRandomIpv4Addrees(int i) { + int idx = getRandomInt(IPV4_FORMATS.length); + return String.format(IPV4_FORMATS[idx], getIpv4Octet(i)); + } + + private int getRandomInt(int upperBound) { + return (int)(Math.random() * upperBound); + } + + private String getRandomIpv6Address(int i, String name) { + int idx = getRandomInt(IPV6_FORMATS.length); + return String.format(IPV6_FORMATS[idx], getIpv6Hextet(i), name); + } + + // package-private for testing + String getIpv6Hextet(int i) { + int remainder = i % IPv6Mod; + if (remainder == 0) { + // 0 isn't really an IP, make it 1 instead. + remainder = 1; + } + return Integer.toHexString(remainder); + } + + // package-private for testing + int getIpv4Octet(int i) { + int remainder = i % IPv4Mod; + if (remainder == 0) { + // 0 is network address, switch to IP + remainder = 1; + } + return remainder; + } + + private String getRandomInterfaceName(int i) { + int idx = getRandomInt(IFACE_NAMES.length); + return IFACE_NAMES[idx] + i; + } + + private NetworkInterfaceDAOCountable getDao(Storage storage) { + if (this.dao == null) { + return new NetworkInterfaceDAOCountable(storage); + } + return dao; + } + + @Override + public String getHandledCollection() { + return NetworkInterfaceInfoDAO.networkInfoCategory.getName(); + } + + static class NetworkInterfaceDAOCountable extends NetworkInterfaceInfoDAOImpl implements Countable { + + private final Category<AggregateCount> aggregateCategory; + private final Storage storage; + + NetworkInterfaceDAOCountable(Storage storage) { + super(storage); + CategoryAdapter<NetworkInterfaceInfo, AggregateCount> adapter = new CategoryAdapter<>(networkInfoCategory); + aggregateCategory = adapter.getAdapted(AggregateCount.class); + storage.registerCategory(aggregateCategory); + this.storage = storage; + } + + @Override + public long getCount() { + String descriptor = "QUERY-COUNT " + networkInfoCategory.getName(); + try { + PreparedStatement<AggregateCount> stmt = storage.prepareStatement(new StatementDescriptor<>(aggregateCategory, descriptor)); + Cursor<AggregateCount> cursor = stmt.executeQuery(); + AggregateCount count = cursor.next(); + return count.getCount(); + } catch (DescriptorParsingException | StatementExecutionException e) { + throw new RuntimeException(e); + } + } + + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/internal/ThreadPopulator.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,282 @@ +/* + * Copyright 2012-2016 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.dev.populator.internal; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import com.redhat.thermostat.common.Pair; +import com.redhat.thermostat.dev.populator.config.ConfigItem; +import com.redhat.thermostat.dev.populator.dependencies.SharedState; +import com.redhat.thermostat.storage.core.Category; +import com.redhat.thermostat.storage.core.CategoryAdapter; +import com.redhat.thermostat.storage.core.Countable; +import com.redhat.thermostat.storage.core.Cursor; +import com.redhat.thermostat.storage.core.DescriptorParsingException; +import com.redhat.thermostat.storage.core.PreparedStatement; +import com.redhat.thermostat.storage.core.StatementDescriptor; +import com.redhat.thermostat.storage.core.StatementExecutionException; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.model.AggregateCount; +import com.redhat.thermostat.thread.dao.ThreadDao; +import com.redhat.thermostat.thread.dao.internal.ThreadDaoImpl; +import com.redhat.thermostat.thread.model.ThreadHarvestingStatus; +import com.redhat.thermostat.thread.model.ThreadSession; +import com.redhat.thermostat.thread.model.ThreadState; +import com.redhat.thermostat.thread.model.ThreadSummary; +import com.redhat.thermostat.thread.model.VmDeadLockData; + +public class ThreadPopulator extends BasePopulator { + + /** + * Package-private and static for testing. + */ + static final int NUM_SAMPLES = 10; + + public final String SESSION = "session"; + private final int NUM_THREADS = 3; + private final long SEED = 5; + Random generator = new Random(SEED); + private static final String[] THREAD_NAMES = new String[] { + "Spencer", "Sheldon", "Alice", "Bob", "Julie", "Phoebe", "Alpha", "Beta", "Gamma", + "Theta", "Zeta", + }; + static final String DEADLOCK_DESC_FORMAT = "" + + "\"%s\" Id=%d WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7 owned by \"%s\" Id=%d\n" + + "\tat sun.misc.Unsafe.park(Native Method)\n" + + "\t- waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7\n" + + "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + + "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" + + "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" + + "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" + + "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" + + "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" + + "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" + + "\t...\n\n" + + "\tNumber of locked synchronizers = 1\n" + + "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2\n" + + "\n\n" + + "\"%s\" Id=%d WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e owned by \"%s\" Id=%d\n" + + "\tat sun.misc.Unsafe.park(Native Method)\n" + + "\t- waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e\n" + + "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + + "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" + + "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" + + "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" + + "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" + + "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" + + "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" + + "\t...\n\n" + + "\tNumber of locked synchronizers = 1\n" + + "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7\n" + + "\n\n" + + "\"%s\" Id=%d WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2 owned by \"%s\" Id=%d\n" + + "\tat sun.misc.Unsafe.park(Native Method)\n" + + "\t- waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2\n" + + "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + + "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" + + "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" + + "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" + + "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" + + "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" + + "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" + + "\t...\n\n" + + "\tNumber of locked synchronizers = 1\n" + + "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e\n\n\n"; + + + private ThreadDaoCountable dao; + + public ThreadPopulator() { + this(null); + } + + ThreadPopulator(ThreadDaoCountable dao) { + this.dao = dao; + } + + // Testing hook + private void createDao(Storage storage) { + if (dao == null) { + dao = new ThreadDaoCountable(storage); + } + } + + @Override + public SharedState addPojos(Storage storage, ConfigItem item, SharedState relState) { + createDao(storage); + // creates records per agent *and* vm + List<String> agentIds = relState.getProcessedRecordsFor("agentId").getAll(); + List<String> vmIds = relState.getProcessedRecordsFor("vmId").getAll(); + int perVmNumber = item.getNumber(); + int totalCount = perVmNumber * agentIds.size() * vmIds.size(); + int currCount = 0; + long countBefore = dao.getCount(); + System.out.println("Populating "+ totalCount + " " + item.getName() + " records"); + long currTime = System.currentTimeMillis(); + for (String agentId: agentIds) { + for (String vmId: vmIds) { + for (int i = 0; i < perVmNumber; i++) { + ThreadSummary summary = new ThreadSummary(); + summary.setAgentId(agentId); + summary.setVmId(vmId); + int liveThreads = generator.nextInt(NUM_THREADS); + summary.setCurrentLiveThreads(liveThreads); + int daemonThreads = NUM_THREADS - liveThreads; + summary.setCurrentDaemonThreads(daemonThreads); + long timeStamp = currTime + i * 1000; + summary.setTimeStamp(timeStamp); + dao.saveSummary(summary); + + ThreadSession session = new ThreadSession(); + session.setSession(SESSION); + session.setTimeStamp(timeStamp); + session.setAgentId(agentId); + session.setVmId(vmId); + dao.saveSession(session); + + final Thread.State[] states = Thread.State.values(); + String state = states[generator.nextInt(states.length)].toString(); + String name = THREAD_NAMES[generator.nextInt(THREAD_NAMES.length)]; + + for(int j = 0; j < NUM_SAMPLES; j++) { + ThreadState threadState = new ThreadState(); + threadState.setTimeStamp(currTime + j * 1000); + threadState.setVmId(vmId); + threadState.setAgentId(agentId); + threadState.setState(state); + threadState.setId(i); + threadState.setName(name); + threadState.setSession(SESSION); + dao.addThreadState(threadState); + } + + ThreadHarvestingStatus status = new ThreadHarvestingStatus(agentId); + status.setVmId(vmId); + status.setTimeStamp(timeStamp); + status.setHarvesting(generator.nextBoolean()); + dao.saveHarvestingStatus(status); + + VmDeadLockData data = new VmDeadLockData(); + data.setAgentId(agentId); + data.setVmId(vmId); + data.setTimeStamp(currTime + i * 10); + data.setDeadLockDescription(getDeadlockedDescription(currCount)); + dao.saveDeadLockStatus(data); + currCount++; + reportProgress(item, currCount); + } + } + } + doWaitUntilCount(dao, countBefore + totalCount); + return relState; + } + + private String getDeadlockedDescription(int currCount) { + return String.format(DEADLOCK_DESC_FORMAT, getFormatStringArgs(currCount)); + } + + Object[] getFormatStringArgs(int currCount) { + List<Pair<String, Integer>> nameIdMapping = new ArrayList<>(); + int[] randomIds = getIdValues(currCount, NUM_THREADS); + int randomEntry = getRandomInt(THREAD_NAMES.length); + for (int i = 0, idx; i < NUM_THREADS; i++) { + idx = (randomEntry + i) % THREAD_NAMES.length; + String name = THREAD_NAMES[idx]; + int tid = randomIds[i]; + nameIdMapping.add(new Pair<>(name, tid)); + } + Object[] formatArgs = new Object[NUM_THREADS * 2 * 2]; + formatArgs[0] = nameIdMapping.get(0).getFirst(); + formatArgs[1] = nameIdMapping.get(0).getSecond(); + for (int i = 2, j = 1; i < formatArgs.length - 2; i+= 4, j++) { + formatArgs[i] = nameIdMapping.get(j).getFirst(); + formatArgs[i + 1] = nameIdMapping.get(j).getSecond(); + formatArgs[i + 2] = nameIdMapping.get(j).getFirst(); + formatArgs[i + 3] = nameIdMapping.get(j).getSecond(); + } + formatArgs[formatArgs.length - 2] = nameIdMapping.get(0).getFirst(); + formatArgs[formatArgs.length - 1] = nameIdMapping.get(0).getSecond(); + return formatArgs; + } + + private int getRandomInt(int len) { + return (int)(Math.random() * len); + } + + private int[] getIdValues(int currCount, int length) { + int[] values = new int[length]; + for (int i = 0; i < values.length; i++) { + values[i] = currCount + i; + } + return values; + } + + @Override + public String getHandledCollection() { + return ThreadDao.THREAD_HARVESTING_STATUS.getName(); + } + + static class ThreadDaoCountable extends ThreadDaoImpl implements Countable { + + private final Category<AggregateCount> aggregateCategory; + private final Storage storage; + + public ThreadDaoCountable(Storage storage) { + super(storage); + CategoryAdapter<VmDeadLockData, AggregateCount> adapter = new CategoryAdapter<>(DEADLOCK_INFO); + aggregateCategory = adapter.getAdapted(AggregateCount.class); + storage.registerCategory(aggregateCategory); + this.storage = storage; + } + + @Override + public long getCount() { + String descriptor = "QUERY-COUNT " + DEADLOCK_INFO.getName(); + try { + PreparedStatement<AggregateCount> stmt = storage.prepareStatement(new StatementDescriptor<>(aggregateCategory, descriptor)); + Cursor<AggregateCount> cursor = stmt.executeQuery(); + AggregateCount count = cursor.next(); + return count.getCount(); + } catch (DescriptorParsingException | StatementExecutionException e) { + throw new RuntimeException(e); + } + } + + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/data-populator/src/main/java/com/redhat/thermostat/dev/populator/internal/VmInfoPopulator.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,154 @@ +/* + * Copyright 2012-2016 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.dev.populator.internal; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import com.redhat.thermostat.dev.populator.config.ConfigItem; +import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords; +import com.redhat.thermostat.dev.populator.dependencies.SharedState; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.dao.VmInfoDAO; +import com.redhat.thermostat.storage.internal.dao.VmInfoDAOImpl; +import com.redhat.thermostat.storage.model.VmInfo; + +public class VmInfoPopulator extends BasePopulator { + + private final VmInfoDAO dao; + + public VmInfoPopulator() { + this(null); + } + + VmInfoPopulator(VmInfoDAO dao) { + this.dao = dao; + } + + @Override + public SharedState addPojos(Storage storage, ConfigItem item, SharedState relState) { + // Default to all alive, if unset + int aliveItems = item.getAliveItems() == ConfigItem.UNSET ? item.getNumber() : item.getAliveItems(); + ProcessedRecords<String> procAgents = relState.getProcessedRecordsFor("agentId"); + List<String> vmIds = new ArrayList<>(); + VmInfoDAO dao = getDao(storage); + List<String> allAgents = procAgents.getAll(); + long countBefore = dao.getCount(); + int totalItems = item.getNumber() * allAgents.size(); + // populate VM records per agentID + System.out.println("Populating "+ totalItems + " " + item.getName() + " records"); + int currVal = 0; + for (String agentId: allAgents) { + for (int i = 0; i < item.getNumber(); i++) { + VmInfo info = new VmInfo(); + info.setAgentId(agentId); + info.setJavaCommandLine("java DataPopulatorProducedVM --vm " + i + " --version"); + info.setJavaHome("/opt/foo/bar/java-1.8.0-openjdk/jre"); + info.setJavaVersion("1.8.0"); + info.setMainClass("com.redhat.thermostat.TestDataPopulator"); + info.setLoadedNativeLibraries(new String[] { "glibc.so", "something.so" }); + info.setProperties(getFakeJavaProperties(i, agentId)); + StartStopTimeStamp ts = getFakeStartStopTimeStamp(i, aliveItems); + info.setStartTimeStamp(ts.startTS); + info.setStopTimeStamp(ts.stopTS); + info.setUsername("vm-user-" + i); + info.setUid(i); + info.setVmArguments("-XX:+UseG1Gc"); + String vmId = UUID.randomUUID().toString(); + info.setVmId(vmId); + vmIds.add(vmId); + info.setVmInfo("OpenJDK 8"); + info.setVmPid(34 + i); + info.setVmVersion("hs 25"); + info.setVmName("Hotspot"); + dao.putVmInfo(info); + reportProgress(item, currVal); + currVal++; + } + } + doWaitUntilCount(dao, countBefore + totalItems); + relState.addProcessedRecords("vmId", new ProcessedRecords<>(vmIds)); + return relState; + } + + private StartStopTimeStamp getFakeStartStopTimeStamp(int num, int aliveItems) { + long currTime = System.currentTimeMillis(); + if (num < aliveItems) { + // create alive timestamp pair + long startTs = Long.MAX_VALUE; + long stopTs = currTime; + return new StartStopTimeStamp(startTs, stopTs); + } + // create dead timestamp pair + return new StartStopTimeStamp(currTime - (1000 + num), currTime - (500 + num)); + } + + private Map<String, String> getFakeJavaProperties(int i, String agentId) { + Map<String, String> props = new HashMap<String, String>(); + props.put("foo", "bar"); + props.put("vm#", Integer.toString(i)); + props.put("agentId", agentId); + return props; + } + + // hook for testing + private VmInfoDAO getDao(Storage storage) { + if (dao == null) { + return new VmInfoDAOImpl(storage); + } else { + return dao; + } + } + + @Override + public String getHandledCollection() { + return VmInfoDAO.vmInfoCategory.getName(); + } + + private static class StartStopTimeStamp { + private final long startTS; + private final long stopTS; + + private StartStopTimeStamp(long start, long stop) { + this.startTS = start; + this.stopTS = stop; + } + } +}
--- a/dev/data-populator/src/main/resources/META-INF/services/com.redhat.thermostat.dev.populator.CollectionPopulator Wed Apr 06 14:52:26 2016 +0200 +++ b/dev/data-populator/src/main/resources/META-INF/services/com.redhat.thermostat.dev.populator.CollectionPopulator Fri Apr 08 13:18:48 2016 +0200 @@ -1,5 +1,5 @@ -com.redhat.thermostat.dev.populator.impl.ThreadPopulator -com.redhat.thermostat.dev.populator.impl.AgentInfoPopulator -com.redhat.thermostat.dev.populator.impl.VmInfoPopulator -com.redhat.thermostat.dev.populator.impl.HostInfoPopulator -com.redhat.thermostat.dev.populator.impl.NetworkInfoPopulator +com.redhat.thermostat.dev.populator.internal.ThreadPopulator +com.redhat.thermostat.dev.populator.internal.AgentInfoPopulator +com.redhat.thermostat.dev.populator.internal.VmInfoPopulator +com.redhat.thermostat.dev.populator.internal.HostInfoPopulator +com.redhat.thermostat.dev.populator.internal.NetworkInfoPopulator
--- a/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/impl/AgentInfoPopulatorTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * Copyright 2012-2016 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.dev.populator.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -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.util.ArrayList; -import java.util.List; - -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.redhat.thermostat.dev.populator.config.ConfigItem; -import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords; -import com.redhat.thermostat.dev.populator.dependencies.SharedState; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.dao.AgentInfoDAO; -import com.redhat.thermostat.storage.model.AgentInformation; - -public class AgentInfoPopulatorTest { - - @Test - public void canHandleAgentInfoCollection() { - AgentInfoPopulator putter = new AgentInfoPopulator(); - assertEquals("agent-config", putter.getHandledCollection()); - } - - @Test - public void canAddPojos() { - int totalRecords = 23; - AgentInfoDAO dao = mock(AgentInfoDAO.class); - // Initially return 0, then return the expected count - when(dao.getCount()).thenReturn(0L).thenReturn((long)totalRecords); - AgentInfoPopulator putter = new AgentInfoPopulator(dao); - ConfigItem item = new ConfigItem(totalRecords, 3, "agent-config"); - SharedState state = new SharedState(); - state = putter.addPojos(mock(Storage.class), item, state); - ArgumentCaptor<AgentInformation> agentInfoCaptor = ArgumentCaptor.forClass(AgentInformation.class); - verify(dao, times(23)).addAgentInformation(agentInfoCaptor.capture()); - List<AgentInformation> agentInfos = agentInfoCaptor.getAllValues(); - List<AgentInformation> filtered = getAliveAgentInfos(agentInfos); - assertEquals(3, filtered.size()); - ProcessedRecords<String> recs = state.getProcessedRecordsFor("agentId"); - assertEquals(23, recs.getAll().size()); - ProcessedRecords<String> notExisting = state.getProcessedRecordsFor("foo-bar"); - assertNull(notExisting); - // FIXME: HostInfo populator needs AgentInfoDAO so we tag the dao - // to the shared state. This test asserts that it does so. - AgentInfoDAO stateDAO = (AgentInfoDAO)state.getProperty("agent-info-dao"); - assertNotNull(stateDAO); - assertSame(stateDAO, dao); - } - - private List<AgentInformation> getAliveAgentInfos(List<AgentInformation> agentInfos) { - List<AgentInformation> aliveInfos = new ArrayList<>(); - for (AgentInformation info: agentInfos) { - if (info.isAlive()) { - aliveInfos.add(info); - } - } - return aliveInfos; - } -}
--- a/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/impl/HostInfoPopulatorTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -/* - * Copyright 2012-2016 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.dev.populator.impl; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.eq; -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.util.Arrays; -import java.util.List; - -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.redhat.thermostat.dev.populator.config.ConfigItem; -import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords; -import com.redhat.thermostat.dev.populator.dependencies.SharedState; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.dao.AgentInfoDAO; -import com.redhat.thermostat.storage.dao.HostInfoDAO; -import com.redhat.thermostat.storage.model.HostInfo; - -public class HostInfoPopulatorTest { - - @Test - public void handlesCorrectCollection() { - HostInfoPopulator populator = new HostInfoPopulator(); - assertEquals("host-info", populator.getHandledCollection()); - } - - @Test - public void canPopulateToStorage() { - String[] agents = new String[] { - "host-agent1", "host-agent2", "host-agent3", "host-agent4" - }; - List<String> agentIds = Arrays.asList(agents); - SharedState state = mock(SharedState.class); - @SuppressWarnings("unchecked") - ProcessedRecords<String> procRecs = mock(ProcessedRecords.class); - when(procRecs.getAll()).thenReturn(agentIds); - when(state.getProcessedRecordsFor(eq("agentId"))).thenReturn(procRecs); - when(state.getProperty(eq("agent-info-dao"))).thenReturn(mock(AgentInfoDAO.class)); - int totalRecords = agents.length; - HostInfoDAO dao = mock(HostInfoDAO.class); - // Initially return 0, then return the expected count - when(dao.getCount()).thenReturn(0L).thenReturn((long)totalRecords); - - ConfigItem config = new ConfigItem(1, ConfigItem.UNSET, "host-info"); - HostInfoPopulator populator = new HostInfoPopulator(dao); - populator.addPojos(mock(Storage.class), config, state); - ArgumentCaptor<HostInfo> captor = ArgumentCaptor.forClass(HostInfo.class); - verify(dao, times(totalRecords)).putHostInfo(captor.capture()); - List<HostInfo> values = captor.getAllValues(); - // ensure no memory values are negative - for (HostInfo info: values) { - if (info.getTotalMemory() < 0) { - throw new AssertionError("Invalid memory value: " + info.getTotalMemory() + " < 0"); - } - } - } -}
--- a/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/impl/NetworkInfoPopulatorTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/* - * Copyright 2012-2016 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.dev.populator.impl; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -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.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.redhat.thermostat.dev.populator.config.ConfigItem; -import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords; -import com.redhat.thermostat.dev.populator.dependencies.SharedState; -import com.redhat.thermostat.dev.populator.impl.NetworkInfoPopulator.NetworkInterfaceDAOCountable; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.model.NetworkInterfaceInfo; - -public class NetworkInfoPopulatorTest { - - @Test - public void canHandleCorrectCollection() { - NetworkInfoPopulator populator = new NetworkInfoPopulator(); - assertEquals("network-info", populator.getHandledCollection()); - } - - @Test - public void testPopulation() { - NetworkInterfaceDAOCountable dao = mock(NetworkInterfaceDAOCountable.class); - NetworkInfoPopulator populator = new NetworkInfoPopulator(dao); - - String[] agentIds = new String[] { - "testAgent1", "testAgent2", "testAgent3", "testAgent4" - }; - int perAgentItems = 100; - int totalRecords = perAgentItems * agentIds.length; - when(dao.getCount()).thenReturn(0L).thenReturn((long)totalRecords); - List<String> agents = Arrays.asList(agentIds); - SharedState state = new SharedState(); - state.addProcessedRecords("agentId", new ProcessedRecords<>(agents)); - ConfigItem config = new ConfigItem(perAgentItems, ConfigItem.UNSET, "network-info"); - populator.addPojos(mock(Storage.class), config, state); - ArgumentCaptor<NetworkInterfaceInfo> captor = ArgumentCaptor.forClass(NetworkInterfaceInfo.class); - verify(dao, times(totalRecords)).putNetworkInterfaceInfo(captor.capture()); - List<NetworkInterfaceInfo> list = captor.getAllValues(); - // expected agentId + iface name to be unique (since REPLACE otherwise replaces some random values) - Set<String> uniqueSet = new HashSet<>(); - for (NetworkInterfaceInfo info: list) { - String agentId = info.getAgentId(); - String ifaceName = info.getInterfaceName(); - String key = agentId + ifaceName; - if (uniqueSet.contains(key)) { - throw new AssertionError("Expected interface names to be unique per agent"); - } else { - uniqueSet.add(key); - } - } - } - - @Test - public void iPv6HextetRollOver() { - String ipv6 = new NetworkInfoPopulator().getIpv6Hextet(Integer.parseInt("fffe", 16)); - assertEquals("fffe", ipv6); - ipv6 = new NetworkInfoPopulator().getIpv6Hextet(Integer.parseInt("ffff", 16)); - assertEquals("1", ipv6); - ipv6 = new NetworkInfoPopulator().getIpv6Hextet(Integer.parseInt("eee1", 16)); - assertEquals("eee1", ipv6); - } - - @Test - public void iPv4OctetsRollOver() { - int octet = new NetworkInfoPopulator().getIpv4Octet(255); - assertEquals(1, octet); - octet = new NetworkInfoPopulator().getIpv4Octet(256); - assertEquals(1, octet); - octet = new NetworkInfoPopulator().getIpv4Octet(114); - assertEquals(114, octet); - } - - @Test - public void stringFormatIpv6Template() { - String formattedString = String.format(NetworkInfoPopulator.IPV6_FORMATS[1], "ff", "scope"); - assertEquals("fe80::56ee:75ff:fe35:ff%scope", formattedString); - } -}
--- a/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/impl/ThreadPopulatorTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,289 +0,0 @@ -/* - * Copyright 2012-2016 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.dev.populator.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -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.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.redhat.thermostat.dev.populator.config.ConfigItem; -import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords; -import com.redhat.thermostat.dev.populator.dependencies.SharedState; -import com.redhat.thermostat.dev.populator.impl.ThreadPopulator.ThreadDaoCountable; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.model.BasePojo; -import com.redhat.thermostat.thread.model.ThreadHarvestingStatus; -import com.redhat.thermostat.thread.model.ThreadSession; -import com.redhat.thermostat.thread.model.ThreadState; -import com.redhat.thermostat.thread.model.ThreadSummary; -import com.redhat.thermostat.thread.model.VmDeadLockData; - -public class ThreadPopulatorTest { - - private static final String EXPECTED_DESCRIPTION = "" + - "\"Mallory\" Id=12 WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7 owned by \"Alice\" Id=10\n" + - "\tat sun.misc.Unsafe.park(Native Method)\n" + - "\t- waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7\n" + - "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + - "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" + - "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" + - "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" + - "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" + - "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" + - "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" + - "\t...\n\n" + - "\tNumber of locked synchronizers = 1\n" + - "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2" + - "\n\n\n" + - "\"Alice\" Id=10 WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e owned by \"Bob\" Id=11\n" + - "\tat sun.misc.Unsafe.park(Native Method)\n" + - "\t- waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e\n" + - "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + - "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" + - "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" + - "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" + - "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" + - "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" + - "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" + - "\t...\n\n" + - "\tNumber of locked synchronizers = 1\n" + - "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7\n" + - "\n\n" + - "\"Bob\" Id=11 WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2 owned by \"Mallory\" Id=12\n" + - "\tat sun.misc.Unsafe.park(Native Method)\n" + - "\t- waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2\n" + - "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + - "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" + - "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" + - "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" + - "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" + - "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" + - "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" + - "\t...\n\n" + - "\tNumber of locked synchronizers = 1\n" + - "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e\n\n\n"; - - private static final String[] AGENTS = new String[] { - "fooAgent1", "fooBarAgent", "testAgent", "someAgent" - }; - private static final String[] VMS = new String[] { - "vm1", "vm2", "vm3", "vm4", "vm5" - }; - - private ThreadDaoCountable countableDao; - - @Test - public void testFormatDeadlockDesc() { - Object[] stringFormatArgs = new Object[] { - "Mallory", 12, - "Alice", 10, - "Alice", 10, - "Bob", 11, - "Bob", 11, - "Mallory", 12 - }; - assertEquals(EXPECTED_DESCRIPTION, String.format(ThreadPopulator.DEADLOCK_DESC_FORMAT, stringFormatArgs)); - } - - @Test - public void canGetRandomThreadNames() { - Object[] args = new ThreadPopulator().getFormatStringArgs(2); - assertEquals(12, args.length); - Map<Integer, Integer> tids = new HashMap<>(); - Map<String, Integer> threadNames = new HashMap<>(); - for (int i = 0; i < args.length; i +=2) { - Object arg1 = args[i]; - Object arg2 = args[i + 1]; - assertEquals(String.class, arg1.getClass()); - assertEquals(Integer.class, arg2.getClass()); - if (tids.containsKey(arg2)) { - Integer value = tids.get(arg2); - value += 1; - tids.put((Integer)arg2, value); - } else { - tids.put((Integer)arg2, 1); - } - if (threadNames.containsKey(arg1)) { - Integer value = threadNames.get(arg1); - value += 1; - threadNames.put((String)arg1, value); - } else { - threadNames.put((String)arg1, 1); - } - } - for (String key : threadNames.keySet()) { - int value = threadNames.get(key); - assertEquals(2, value); - } - for (Integer key : tids.keySet()) { - int value = tids.get(key); - assertEquals(2, value); - } - } - - @Test - public void canHandleAppropriateCollection() { - ThreadPopulator populator = new ThreadPopulator(); - assertEquals("vm-thread-harvesting", populator.getHandledCollection()); - } - - @Test - public void canAddThreadData() { - int perVmCount = 123; - int totalCount = perVmCount * AGENTS.length * VMS.length; - setUp(perVmCount, totalCount); - - assertThreadSummaries(totalCount, perVmCount); - assertThreadSessions(totalCount, perVmCount); - assertThreadStates(totalCount, perVmCount); - assertThreadHarvestingStatus(totalCount, perVmCount); - assertDeadlockInfo(perVmCount, totalCount); - } - - private void setUp(int perVmCount, int totalCount) { - ConfigItem config = new ConfigItem(perVmCount, ConfigItem.UNSET, "vm-deadlock-data"); - countableDao = mock(ThreadDaoCountable.class); - when(countableDao.getCount()).thenReturn(0L).thenReturn((long)totalCount); - ThreadPopulator populator = new ThreadPopulator(countableDao); - SharedState state = mock(SharedState.class); - when(state.getProcessedRecordsFor("agentId")).thenReturn(new ProcessedRecords<>(Arrays.asList(AGENTS))); - when(state.getProcessedRecordsFor("vmId")).thenReturn(new ProcessedRecords<>(Arrays.asList(VMS))); - SharedState retval = populator.addPojos(mock(Storage.class), config, state); - assertSame(retval, state); - } - - private void assertThreadSummaries(int totalCount, int perVmCount) { - ArgumentCaptor<ThreadSummary> summaryCaptor = ArgumentCaptor.forClass(ThreadSummary.class); - verify(countableDao, times(totalCount)).saveSummary(summaryCaptor.capture()); - List<ThreadSummary> savedValues = summaryCaptor.getAllValues(); - assertEquals(totalCount, savedValues.size()); - checkInstances(savedValues, VMS.length * perVmCount); - } - - private void assertThreadSessions(int totalCount, int perVmCount) { - ArgumentCaptor<ThreadSession> sessionCaptor = ArgumentCaptor.forClass(ThreadSession.class); - verify(countableDao, times(totalCount)).saveSession(sessionCaptor.capture()); - List<ThreadSession> savedValues = sessionCaptor.getAllValues(); - assertEquals(totalCount, savedValues.size()); - checkInstances(savedValues, VMS.length * perVmCount); - } - - private void assertThreadStates(int totalCount, int perVmCount) { - ArgumentCaptor<ThreadState> stateCaptor = ArgumentCaptor.forClass(ThreadState.class); - verify(countableDao, times(totalCount * ThreadPopulator.NUM_SAMPLES)). - addThreadState(stateCaptor.capture()); - List<ThreadState> savedValues = stateCaptor.getAllValues(); - assertEquals(totalCount * ThreadPopulator.NUM_SAMPLES, savedValues.size()); - checkInstances(savedValues, VMS.length * perVmCount * ThreadPopulator.NUM_SAMPLES); - } - - private void assertThreadHarvestingStatus(int totalCount, int perVmCount) { - ArgumentCaptor<ThreadHarvestingStatus> statusCaptor = - ArgumentCaptor.forClass(ThreadHarvestingStatus.class); - verify(countableDao, times(totalCount)).saveHarvestingStatus(statusCaptor.capture()); - List<ThreadHarvestingStatus> savedValues = statusCaptor.getAllValues(); - checkInstances(savedValues, VMS.length * perVmCount); - } - - private void checkInstances(List<? extends BasePojo> savedValues, int expected) { - List<String> agentIds = new ArrayList<>(); - for (int i = 0; i < savedValues.size(); i++) { - agentIds.add(savedValues.get(i).getAgentId()); - } - - for (String agentId : AGENTS) { - int numInstances = Collections.frequency(agentIds, agentId); - assertEquals(expected, numInstances); - } - } - - private void assertDeadlockInfo(int perVmCount, int totalCount) { - ArgumentCaptor<VmDeadLockData> deadlockInfoCaptor = ArgumentCaptor.forClass(VmDeadLockData.class); - verify(countableDao, times(totalCount)).saveDeadLockStatus(deadlockInfoCaptor.capture()); - List<VmDeadLockData> savedValues = deadlockInfoCaptor.getAllValues(); - assertEquals(totalCount, savedValues.size()); - List<VmDeadLockData> perVmIdAgentDeadlockData = getFilteredByVmId(savedValues, "vm3"); - assertEquals(perVmCount * AGENTS.length, perVmIdAgentDeadlockData.size()); - List<VmDeadLockData> perAgentIdDeadlockData = getFilteredByAgentId(savedValues, "fooAgent1"); - verifyVmIdsDifferent(perAgentIdDeadlockData); - } - - private List<VmDeadLockData> getFilteredByAgentId(List<VmDeadLockData> perVmDeadlockData, String agentId) { - List<VmDeadLockData> filteredValues = new ArrayList<>(); - for (VmDeadLockData data: perVmDeadlockData) { - if (data.getAgentId().equals(agentId)) { - filteredValues.add(data); - } - } - return filteredValues; - } - - private void verifyVmIdsDifferent(List<VmDeadLockData> perVmDeadlockData) { - Set<String> vmIds = new HashSet<>(); - for (VmDeadLockData data: perVmDeadlockData) { - if (vmIds.contains(data.getVmId())) { - throw new AssertionError("Duplicate VM ID per agent. Duplicate was: " + data.getVmId()); - } - vmIds.add(data.getAgentId()); - } - } - - private List<VmDeadLockData> getFilteredByVmId(List<VmDeadLockData> savedValues, String vmId) { - List<VmDeadLockData> filteredValues = new ArrayList<>(); - for (VmDeadLockData data: savedValues) { - if (data.getVmId().equals(vmId)) { - filteredValues.add(data); - } - } - return filteredValues; - } -}
--- a/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/impl/VmInfoPopulatorTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -/* - * Copyright 2012-2016 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.dev.populator.impl; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.eq; -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.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.redhat.thermostat.dev.populator.config.ConfigItem; -import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords; -import com.redhat.thermostat.dev.populator.dependencies.SharedState; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.dao.VmInfoDAO; -import com.redhat.thermostat.storage.model.VmInfo; - -public class VmInfoPopulatorTest { - - @Test - public void canHandleCorrectCollection() { - VmInfoPopulator populator = new VmInfoPopulator(); - assertEquals("vm-info", populator.getHandledCollection()); - } - - @SuppressWarnings("unchecked") - @Test - public void canPopulateData() { - VmInfoDAO mockDAO = mock(VmInfoDAO.class); - SharedState state = mock(SharedState.class); - ProcessedRecords<String> procRecs = mock(ProcessedRecords.class); - String[] agents = new String[] { - "foo-agent1", "foo-agent2", "bar-agent3" - }; - List<String> agentIdList = Arrays.asList(agents); - when(procRecs.getAll()).thenReturn(agentIdList); - when(state.getProcessedRecordsFor(eq("agentId"))).thenReturn(procRecs); - int perAgentVms = 44; - int subsetAlive = 23; - ConfigItem config = new ConfigItem(perAgentVms, subsetAlive, "vm-info"); - - // total records inserted will be 3 * 44. 44 records per agentId - int totalRecords = perAgentVms * agents.length; - // Initially return 0, then return the expected count - when(mockDAO.getCount()).thenReturn(0L).thenReturn((long)totalRecords); - VmInfoPopulator populator = new VmInfoPopulator(mockDAO); - populator.addPojos(mock(Storage.class), config, state); - ArgumentCaptor<VmInfo> captor = ArgumentCaptor.forClass(VmInfo.class); - verify(mockDAO, times(totalRecords)).putVmInfo(captor.capture()); - List<VmInfo> allInfos = captor.getAllValues(); - assertEquals(totalRecords, allInfos.size()); - List<VmInfo> aliveInfos = getAliveVmInfos(allInfos); - int totalAliveRecs = subsetAlive * agents.length; - assertEquals(totalAliveRecs, aliveInfos.size()); - @SuppressWarnings("rawtypes") - ArgumentCaptor<ProcessedRecords> procsVms = ArgumentCaptor.forClass(ProcessedRecords.class); - verify(state).addProcessedRecords(eq("vmId"), procsVms.capture()); - ProcessedRecords<String> processedVms = procsVms.getValue(); - assertEquals("Excected vmIds added to shared state", totalRecords, processedVms.getAll().size()); - } - - @SuppressWarnings("deprecation") - private List<VmInfo> getAliveVmInfos(List<VmInfo> allInfos) { - List<VmInfo> aliveInfos = new ArrayList<>(); - for (VmInfo info: allInfos) { - if (info.isAlive()) { - aliveInfos.add(info); - } - } - return aliveInfos; - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/internal/AgentInfoPopulatorTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,104 @@ +/* + * Copyright 2012-2016 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.dev.populator.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +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.util.ArrayList; +import java.util.List; + +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.dev.populator.config.ConfigItem; +import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords; +import com.redhat.thermostat.dev.populator.dependencies.SharedState; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.storage.model.AgentInformation; + +public class AgentInfoPopulatorTest { + + @Test + public void canHandleAgentInfoCollection() { + AgentInfoPopulator putter = new AgentInfoPopulator(); + assertEquals("agent-config", putter.getHandledCollection()); + } + + @Test + public void canAddPojos() { + int totalRecords = 23; + AgentInfoDAO dao = mock(AgentInfoDAO.class); + // Initially return 0, then return the expected count + when(dao.getCount()).thenReturn(0L).thenReturn((long)totalRecords); + AgentInfoPopulator putter = new AgentInfoPopulator(dao); + ConfigItem item = new ConfigItem(totalRecords, 3, "agent-config"); + SharedState state = new SharedState(); + state = putter.addPojos(mock(Storage.class), item, state); + ArgumentCaptor<AgentInformation> agentInfoCaptor = ArgumentCaptor.forClass(AgentInformation.class); + verify(dao, times(23)).addAgentInformation(agentInfoCaptor.capture()); + List<AgentInformation> agentInfos = agentInfoCaptor.getAllValues(); + List<AgentInformation> filtered = getAliveAgentInfos(agentInfos); + assertEquals(3, filtered.size()); + ProcessedRecords<String> recs = state.getProcessedRecordsFor("agentId"); + assertEquals(23, recs.getAll().size()); + ProcessedRecords<String> notExisting = state.getProcessedRecordsFor("foo-bar"); + assertNull(notExisting); + // FIXME: HostInfo populator needs AgentInfoDAO so we tag the dao + // to the shared state. This test asserts that it does so. + AgentInfoDAO stateDAO = (AgentInfoDAO)state.getProperty("agent-info-dao"); + assertNotNull(stateDAO); + assertSame(stateDAO, dao); + } + + private List<AgentInformation> getAliveAgentInfos(List<AgentInformation> agentInfos) { + List<AgentInformation> aliveInfos = new ArrayList<>(); + for (AgentInformation info: agentInfos) { + if (info.isAlive()) { + aliveInfos.add(info); + } + } + return aliveInfos; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/internal/HostInfoPopulatorTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,98 @@ +/* + * Copyright 2012-2016 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.dev.populator.internal; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.eq; +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.util.Arrays; +import java.util.List; + +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.dev.populator.config.ConfigItem; +import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords; +import com.redhat.thermostat.dev.populator.dependencies.SharedState; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.storage.dao.HostInfoDAO; +import com.redhat.thermostat.storage.model.HostInfo; + +public class HostInfoPopulatorTest { + + @Test + public void handlesCorrectCollection() { + HostInfoPopulator populator = new HostInfoPopulator(); + assertEquals("host-info", populator.getHandledCollection()); + } + + @Test + public void canPopulateToStorage() { + String[] agents = new String[] { + "host-agent1", "host-agent2", "host-agent3", "host-agent4" + }; + List<String> agentIds = Arrays.asList(agents); + SharedState state = mock(SharedState.class); + @SuppressWarnings("unchecked") + ProcessedRecords<String> procRecs = mock(ProcessedRecords.class); + when(procRecs.getAll()).thenReturn(agentIds); + when(state.getProcessedRecordsFor(eq("agentId"))).thenReturn(procRecs); + when(state.getProperty(eq("agent-info-dao"))).thenReturn(mock(AgentInfoDAO.class)); + int totalRecords = agents.length; + HostInfoDAO dao = mock(HostInfoDAO.class); + // Initially return 0, then return the expected count + when(dao.getCount()).thenReturn(0L).thenReturn((long)totalRecords); + + ConfigItem config = new ConfigItem(1, ConfigItem.UNSET, "host-info"); + HostInfoPopulator populator = new HostInfoPopulator(dao); + populator.addPojos(mock(Storage.class), config, state); + ArgumentCaptor<HostInfo> captor = ArgumentCaptor.forClass(HostInfo.class); + verify(dao, times(totalRecords)).putHostInfo(captor.capture()); + List<HostInfo> values = captor.getAllValues(); + // ensure no memory values are negative + for (HostInfo info: values) { + if (info.getTotalMemory() < 0) { + throw new AssertionError("Invalid memory value: " + info.getTotalMemory() + " < 0"); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/internal/NetworkInfoPopulatorTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,126 @@ +/* + * Copyright 2012-2016 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.dev.populator.internal; + +import static org.junit.Assert.assertEquals; +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.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.dev.populator.config.ConfigItem; +import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords; +import com.redhat.thermostat.dev.populator.dependencies.SharedState; +import com.redhat.thermostat.dev.populator.internal.NetworkInfoPopulator.NetworkInterfaceDAOCountable; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.model.NetworkInterfaceInfo; + +public class NetworkInfoPopulatorTest { + + @Test + public void canHandleCorrectCollection() { + NetworkInfoPopulator populator = new NetworkInfoPopulator(); + assertEquals("network-info", populator.getHandledCollection()); + } + + @Test + public void testPopulation() { + NetworkInterfaceDAOCountable dao = mock(NetworkInterfaceDAOCountable.class); + NetworkInfoPopulator populator = new NetworkInfoPopulator(dao); + + String[] agentIds = new String[] { + "testAgent1", "testAgent2", "testAgent3", "testAgent4" + }; + int perAgentItems = 100; + int totalRecords = perAgentItems * agentIds.length; + when(dao.getCount()).thenReturn(0L).thenReturn((long)totalRecords); + List<String> agents = Arrays.asList(agentIds); + SharedState state = new SharedState(); + state.addProcessedRecords("agentId", new ProcessedRecords<>(agents)); + ConfigItem config = new ConfigItem(perAgentItems, ConfigItem.UNSET, "network-info"); + populator.addPojos(mock(Storage.class), config, state); + ArgumentCaptor<NetworkInterfaceInfo> captor = ArgumentCaptor.forClass(NetworkInterfaceInfo.class); + verify(dao, times(totalRecords)).putNetworkInterfaceInfo(captor.capture()); + List<NetworkInterfaceInfo> list = captor.getAllValues(); + // expected agentId + iface name to be unique (since REPLACE otherwise replaces some random values) + Set<String> uniqueSet = new HashSet<>(); + for (NetworkInterfaceInfo info: list) { + String agentId = info.getAgentId(); + String ifaceName = info.getInterfaceName(); + String key = agentId + ifaceName; + if (uniqueSet.contains(key)) { + throw new AssertionError("Expected interface names to be unique per agent"); + } else { + uniqueSet.add(key); + } + } + } + + @Test + public void iPv6HextetRollOver() { + String ipv6 = new NetworkInfoPopulator().getIpv6Hextet(Integer.parseInt("fffe", 16)); + assertEquals("fffe", ipv6); + ipv6 = new NetworkInfoPopulator().getIpv6Hextet(Integer.parseInt("ffff", 16)); + assertEquals("1", ipv6); + ipv6 = new NetworkInfoPopulator().getIpv6Hextet(Integer.parseInt("eee1", 16)); + assertEquals("eee1", ipv6); + } + + @Test + public void iPv4OctetsRollOver() { + int octet = new NetworkInfoPopulator().getIpv4Octet(255); + assertEquals(1, octet); + octet = new NetworkInfoPopulator().getIpv4Octet(256); + assertEquals(1, octet); + octet = new NetworkInfoPopulator().getIpv4Octet(114); + assertEquals(114, octet); + } + + @Test + public void stringFormatIpv6Template() { + String formattedString = String.format(NetworkInfoPopulator.IPV6_FORMATS[1], "ff", "scope"); + assertEquals("fe80::56ee:75ff:fe35:ff%scope", formattedString); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/internal/ThreadPopulatorTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,289 @@ +/* + * Copyright 2012-2016 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.dev.populator.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +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.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.dev.populator.config.ConfigItem; +import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords; +import com.redhat.thermostat.dev.populator.dependencies.SharedState; +import com.redhat.thermostat.dev.populator.internal.ThreadPopulator.ThreadDaoCountable; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.model.BasePojo; +import com.redhat.thermostat.thread.model.ThreadHarvestingStatus; +import com.redhat.thermostat.thread.model.ThreadSession; +import com.redhat.thermostat.thread.model.ThreadState; +import com.redhat.thermostat.thread.model.ThreadSummary; +import com.redhat.thermostat.thread.model.VmDeadLockData; + +public class ThreadPopulatorTest { + + private static final String EXPECTED_DESCRIPTION = "" + + "\"Mallory\" Id=12 WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7 owned by \"Alice\" Id=10\n" + + "\tat sun.misc.Unsafe.park(Native Method)\n" + + "\t- waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7\n" + + "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + + "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" + + "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" + + "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" + + "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" + + "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" + + "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" + + "\t...\n\n" + + "\tNumber of locked synchronizers = 1\n" + + "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2" + + "\n\n\n" + + "\"Alice\" Id=10 WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e owned by \"Bob\" Id=11\n" + + "\tat sun.misc.Unsafe.park(Native Method)\n" + + "\t- waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e\n" + + "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + + "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" + + "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" + + "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" + + "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" + + "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" + + "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" + + "\t...\n\n" + + "\tNumber of locked synchronizers = 1\n" + + "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@52de95c7\n" + + "\n\n" + + "\"Bob\" Id=11 WAITING on java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2 owned by \"Mallory\" Id=12\n" + + "\tat sun.misc.Unsafe.park(Native Method)\n" + + "\t- waiting on java.util.concurrent.locks.ReentrantLock$NonfairSync@441634c2\n" + + "\tat java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\n" + + "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)\n" + + "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)\n" + + "\tat java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)\n" + + "\tat java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)\n" + + "\tat java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)\n" + + "\tat com.redhat.thermostat.tests.DeadLock$Philosopher.run(DeadLock.java:57)\n" + + "\t...\n\n" + + "\tNumber of locked synchronizers = 1\n" + + "\t- java.util.concurrent.locks.ReentrantLock$NonfairSync@105ff84e\n\n\n"; + + private static final String[] AGENTS = new String[] { + "fooAgent1", "fooBarAgent", "testAgent", "someAgent" + }; + private static final String[] VMS = new String[] { + "vm1", "vm2", "vm3", "vm4", "vm5" + }; + + private ThreadDaoCountable countableDao; + + @Test + public void testFormatDeadlockDesc() { + Object[] stringFormatArgs = new Object[] { + "Mallory", 12, + "Alice", 10, + "Alice", 10, + "Bob", 11, + "Bob", 11, + "Mallory", 12 + }; + assertEquals(EXPECTED_DESCRIPTION, String.format(ThreadPopulator.DEADLOCK_DESC_FORMAT, stringFormatArgs)); + } + + @Test + public void canGetRandomThreadNames() { + Object[] args = new ThreadPopulator().getFormatStringArgs(2); + assertEquals(12, args.length); + Map<Integer, Integer> tids = new HashMap<>(); + Map<String, Integer> threadNames = new HashMap<>(); + for (int i = 0; i < args.length; i +=2) { + Object arg1 = args[i]; + Object arg2 = args[i + 1]; + assertEquals(String.class, arg1.getClass()); + assertEquals(Integer.class, arg2.getClass()); + if (tids.containsKey(arg2)) { + Integer value = tids.get(arg2); + value += 1; + tids.put((Integer)arg2, value); + } else { + tids.put((Integer)arg2, 1); + } + if (threadNames.containsKey(arg1)) { + Integer value = threadNames.get(arg1); + value += 1; + threadNames.put((String)arg1, value); + } else { + threadNames.put((String)arg1, 1); + } + } + for (String key : threadNames.keySet()) { + int value = threadNames.get(key); + assertEquals(2, value); + } + for (Integer key : tids.keySet()) { + int value = tids.get(key); + assertEquals(2, value); + } + } + + @Test + public void canHandleAppropriateCollection() { + ThreadPopulator populator = new ThreadPopulator(); + assertEquals("vm-thread-harvesting", populator.getHandledCollection()); + } + + @Test + public void canAddThreadData() { + int perVmCount = 123; + int totalCount = perVmCount * AGENTS.length * VMS.length; + setUp(perVmCount, totalCount); + + assertThreadSummaries(totalCount, perVmCount); + assertThreadSessions(totalCount, perVmCount); + assertThreadStates(totalCount, perVmCount); + assertThreadHarvestingStatus(totalCount, perVmCount); + assertDeadlockInfo(perVmCount, totalCount); + } + + private void setUp(int perVmCount, int totalCount) { + ConfigItem config = new ConfigItem(perVmCount, ConfigItem.UNSET, "vm-deadlock-data"); + countableDao = mock(ThreadDaoCountable.class); + when(countableDao.getCount()).thenReturn(0L).thenReturn((long)totalCount); + ThreadPopulator populator = new ThreadPopulator(countableDao); + SharedState state = mock(SharedState.class); + when(state.getProcessedRecordsFor("agentId")).thenReturn(new ProcessedRecords<>(Arrays.asList(AGENTS))); + when(state.getProcessedRecordsFor("vmId")).thenReturn(new ProcessedRecords<>(Arrays.asList(VMS))); + SharedState retval = populator.addPojos(mock(Storage.class), config, state); + assertSame(retval, state); + } + + private void assertThreadSummaries(int totalCount, int perVmCount) { + ArgumentCaptor<ThreadSummary> summaryCaptor = ArgumentCaptor.forClass(ThreadSummary.class); + verify(countableDao, times(totalCount)).saveSummary(summaryCaptor.capture()); + List<ThreadSummary> savedValues = summaryCaptor.getAllValues(); + assertEquals(totalCount, savedValues.size()); + checkInstances(savedValues, VMS.length * perVmCount); + } + + private void assertThreadSessions(int totalCount, int perVmCount) { + ArgumentCaptor<ThreadSession> sessionCaptor = ArgumentCaptor.forClass(ThreadSession.class); + verify(countableDao, times(totalCount)).saveSession(sessionCaptor.capture()); + List<ThreadSession> savedValues = sessionCaptor.getAllValues(); + assertEquals(totalCount, savedValues.size()); + checkInstances(savedValues, VMS.length * perVmCount); + } + + private void assertThreadStates(int totalCount, int perVmCount) { + ArgumentCaptor<ThreadState> stateCaptor = ArgumentCaptor.forClass(ThreadState.class); + verify(countableDao, times(totalCount * ThreadPopulator.NUM_SAMPLES)). + addThreadState(stateCaptor.capture()); + List<ThreadState> savedValues = stateCaptor.getAllValues(); + assertEquals(totalCount * ThreadPopulator.NUM_SAMPLES, savedValues.size()); + checkInstances(savedValues, VMS.length * perVmCount * ThreadPopulator.NUM_SAMPLES); + } + + private void assertThreadHarvestingStatus(int totalCount, int perVmCount) { + ArgumentCaptor<ThreadHarvestingStatus> statusCaptor = + ArgumentCaptor.forClass(ThreadHarvestingStatus.class); + verify(countableDao, times(totalCount)).saveHarvestingStatus(statusCaptor.capture()); + List<ThreadHarvestingStatus> savedValues = statusCaptor.getAllValues(); + checkInstances(savedValues, VMS.length * perVmCount); + } + + private void checkInstances(List<? extends BasePojo> savedValues, int expected) { + List<String> agentIds = new ArrayList<>(); + for (int i = 0; i < savedValues.size(); i++) { + agentIds.add(savedValues.get(i).getAgentId()); + } + + for (String agentId : AGENTS) { + int numInstances = Collections.frequency(agentIds, agentId); + assertEquals(expected, numInstances); + } + } + + private void assertDeadlockInfo(int perVmCount, int totalCount) { + ArgumentCaptor<VmDeadLockData> deadlockInfoCaptor = ArgumentCaptor.forClass(VmDeadLockData.class); + verify(countableDao, times(totalCount)).saveDeadLockStatus(deadlockInfoCaptor.capture()); + List<VmDeadLockData> savedValues = deadlockInfoCaptor.getAllValues(); + assertEquals(totalCount, savedValues.size()); + List<VmDeadLockData> perVmIdAgentDeadlockData = getFilteredByVmId(savedValues, "vm3"); + assertEquals(perVmCount * AGENTS.length, perVmIdAgentDeadlockData.size()); + List<VmDeadLockData> perAgentIdDeadlockData = getFilteredByAgentId(savedValues, "fooAgent1"); + verifyVmIdsDifferent(perAgentIdDeadlockData); + } + + private List<VmDeadLockData> getFilteredByAgentId(List<VmDeadLockData> perVmDeadlockData, String agentId) { + List<VmDeadLockData> filteredValues = new ArrayList<>(); + for (VmDeadLockData data: perVmDeadlockData) { + if (data.getAgentId().equals(agentId)) { + filteredValues.add(data); + } + } + return filteredValues; + } + + private void verifyVmIdsDifferent(List<VmDeadLockData> perVmDeadlockData) { + Set<String> vmIds = new HashSet<>(); + for (VmDeadLockData data: perVmDeadlockData) { + if (vmIds.contains(data.getVmId())) { + throw new AssertionError("Duplicate VM ID per agent. Duplicate was: " + data.getVmId()); + } + vmIds.add(data.getAgentId()); + } + } + + private List<VmDeadLockData> getFilteredByVmId(List<VmDeadLockData> savedValues, String vmId) { + List<VmDeadLockData> filteredValues = new ArrayList<>(); + for (VmDeadLockData data: savedValues) { + if (data.getVmId().equals(vmId)) { + filteredValues.add(data); + } + } + return filteredValues; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/data-populator/src/test/java/com/redhat/thermostat/dev/populator/internal/VmInfoPopulatorTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,114 @@ +/* + * Copyright 2012-2016 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.dev.populator.internal; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.eq; +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.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.dev.populator.config.ConfigItem; +import com.redhat.thermostat.dev.populator.dependencies.ProcessedRecords; +import com.redhat.thermostat.dev.populator.dependencies.SharedState; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.dao.VmInfoDAO; +import com.redhat.thermostat.storage.model.VmInfo; + +public class VmInfoPopulatorTest { + + @Test + public void canHandleCorrectCollection() { + VmInfoPopulator populator = new VmInfoPopulator(); + assertEquals("vm-info", populator.getHandledCollection()); + } + + @SuppressWarnings("unchecked") + @Test + public void canPopulateData() { + VmInfoDAO mockDAO = mock(VmInfoDAO.class); + SharedState state = mock(SharedState.class); + ProcessedRecords<String> procRecs = mock(ProcessedRecords.class); + String[] agents = new String[] { + "foo-agent1", "foo-agent2", "bar-agent3" + }; + List<String> agentIdList = Arrays.asList(agents); + when(procRecs.getAll()).thenReturn(agentIdList); + when(state.getProcessedRecordsFor(eq("agentId"))).thenReturn(procRecs); + int perAgentVms = 44; + int subsetAlive = 23; + ConfigItem config = new ConfigItem(perAgentVms, subsetAlive, "vm-info"); + + // total records inserted will be 3 * 44. 44 records per agentId + int totalRecords = perAgentVms * agents.length; + // Initially return 0, then return the expected count + when(mockDAO.getCount()).thenReturn(0L).thenReturn((long)totalRecords); + VmInfoPopulator populator = new VmInfoPopulator(mockDAO); + populator.addPojos(mock(Storage.class), config, state); + ArgumentCaptor<VmInfo> captor = ArgumentCaptor.forClass(VmInfo.class); + verify(mockDAO, times(totalRecords)).putVmInfo(captor.capture()); + List<VmInfo> allInfos = captor.getAllValues(); + assertEquals(totalRecords, allInfos.size()); + List<VmInfo> aliveInfos = getAliveVmInfos(allInfos); + int totalAliveRecs = subsetAlive * agents.length; + assertEquals(totalAliveRecs, aliveInfos.size()); + @SuppressWarnings("rawtypes") + ArgumentCaptor<ProcessedRecords> procsVms = ArgumentCaptor.forClass(ProcessedRecords.class); + verify(state).addProcessedRecords(eq("vmId"), procsVms.capture()); + ProcessedRecords<String> processedVms = procsVms.getValue(); + assertEquals("Excected vmIds added to shared state", totalRecords, processedVms.getAll().size()); + } + + @SuppressWarnings("deprecation") + private List<VmInfo> getAliveVmInfos(List<VmInfo> allInfos) { + List<VmInfo> aliveInfos = new ArrayList<>(); + for (VmInfo info: allInfos) { + if (info.isAlive()) { + aliveInfos.add(info); + } + } + return aliveInfos; + } +}
--- a/distribution/packaging/fedora/0001_shared_fix_bundle_loading.patch Wed Apr 06 14:52:26 2016 +0200 +++ b/distribution/packaging/fedora/0001_shared_fix_bundle_loading.patch Fri Apr 08 13:18:48 2016 +0200 @@ -180,9 +180,9 @@ </bundles> </command> </commands> -diff --git a/main/src/main/resources/com/redhat/thermostat/main/impl/bootstrapbundles.properties b/main/src/main/resources/com/redhat/thermostat/main/impl/bootstrapbundles.properties ---- a/main/src/main/resources/com/redhat/thermostat/main/impl/bootstrapbundles.properties -+++ b/main/src/main/resources/com/redhat/thermostat/main/impl/bootstrapbundles.properties +diff --git a/main/src/main/resources/com/redhat/thermostat/main/internal/bootstrapbundles.properties b/main/src/main/resources/com/redhat/thermostat/main/internal/bootstrapbundles.properties +--- a/main/src/main/resources/com/redhat/thermostat/main/internal/bootstrapbundles.properties ++++ b/main/src/main/resources/com/redhat/thermostat/main/internal/bootstrapbundles.properties @@ -6,4 +6,8 @@ thermostat-launcher-${project.version}.jar, \ jline-${jline.version}.jar, \
--- a/distribution/packaging/fedora/thermostat.spec Wed Apr 06 14:52:26 2016 +0200 +++ b/distribution/packaging/fedora/thermostat.spec Fri Apr 08 13:18:48 2016 +0200 @@ -686,7 +686,7 @@ -d target/classes \ src/main/java/com/redhat/thermostat/utils/keyring/Keyring.java \ src/main/java/com/redhat/thermostat/utils/keyring/KeyringException.java \ - src/main/java/com/redhat/thermostat/utils/keyring/impl/KeyringImpl.java + src/main/java/com/redhat/thermostat/utils/keyring/internal/KeyringImpl.java autoreconf --install ./configure make all
--- a/keyring/pom.xml Wed Apr 06 14:52:26 2016 +0200 +++ b/keyring/pom.xml Fri Apr 08 13:18:48 2016 +0200 @@ -60,7 +60,7 @@ <Bundle-SymbolicName>com.redhat.thermostat.keyring</Bundle-SymbolicName> <Private-Package> com.redhat.thermostat.utils.keyring.activator, - com.redhat.thermostat.utils.keyring.impl, + com.redhat.thermostat.utils.keyring.internal, </Private-Package> <Export-Package>com.redhat.thermostat.utils.keyring</Export-Package> <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
--- a/keyring/src/main/java/com/redhat/thermostat/utils/keyring/activator/Activator.java Wed Apr 06 14:52:26 2016 +0200 +++ b/keyring/src/main/java/com/redhat/thermostat/utils/keyring/activator/Activator.java Fri Apr 08 13:18:48 2016 +0200 @@ -40,7 +40,7 @@ import org.osgi.framework.BundleContext; import com.redhat.thermostat.utils.keyring.Keyring; -import com.redhat.thermostat.utils.keyring.impl.KeyringImpl; +import com.redhat.thermostat.utils.keyring.internal.KeyringImpl; public class Activator implements BundleActivator {
--- a/keyring/src/main/java/com/redhat/thermostat/utils/keyring/impl/KeyringImpl.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -/* - * Copyright 2012-2016 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.utils.keyring.impl; - -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.util.Arrays; - -import com.redhat.thermostat.shared.config.NativeLibraryResolver; -import com.redhat.thermostat.utils.keyring.Keyring; -import com.redhat.thermostat.utils.keyring.KeyringException; - -public class KeyringImpl implements Keyring { - - private static String DESC_PREFIX = "Thermostat auth info for: "; - - static { - String lib = NativeLibraryResolver.getAbsoluteLibraryPath("GnomeKeyringWrapper"); - System.load(lib); - } - - @Override - public synchronized void savePassword(String url, String username, char[] password) { - byte[] pwBytes = null; - boolean success = false; - try { - String desc = DESC_PREFIX + username + "@" + url; - if (password == null) { - pwBytes = new byte[]{}; - } else { - pwBytes = Charset.defaultCharset().encode(CharBuffer.wrap(password)).array(); - } - success = gnomeKeyringWrapperSavePasswordNative(url, username, pwBytes, desc); - } finally { - if (pwBytes != null) { - Arrays.fill(pwBytes, (byte) 0); - } - } - if (!success) { - throw new KeyringException("Couldn't save password."); - } - } - - @Override - public synchronized char[] getPassword(String url, String username) { - byte[] pwBytes = gnomeKeyringWrapperGetPasswordNative(url, username); - char[] password = null; - if (pwBytes != null) { - try { - password = Charset.defaultCharset().decode(ByteBuffer.wrap(pwBytes)).array(); - } finally { - Arrays.fill(pwBytes, (byte) 0); - } - } - return password; - } - - @Override - public synchronized void clearPassword(String url, String username) { - if (!gnomeKeyringWrapperClearPasswordNative(url, username)) { - throw new RuntimeException("Couldn't clear password."); - } - - } - - private static native boolean gnomeKeyringWrapperSavePasswordNative(String url, String userName, byte[] password, String description); - private static native byte[] gnomeKeyringWrapperGetPasswordNative(String url, String userName); - private static native boolean gnomeKeyringWrapperClearPasswordNative(String url, String userName); -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/keyring/src/main/java/com/redhat/thermostat/utils/keyring/internal/KeyringImpl.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,105 @@ +/* + * Copyright 2012-2016 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.utils.keyring.internal; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.util.Arrays; + +import com.redhat.thermostat.shared.config.NativeLibraryResolver; +import com.redhat.thermostat.utils.keyring.Keyring; +import com.redhat.thermostat.utils.keyring.KeyringException; + +public class KeyringImpl implements Keyring { + + private static String DESC_PREFIX = "Thermostat auth info for: "; + + static { + String lib = NativeLibraryResolver.getAbsoluteLibraryPath("GnomeKeyringWrapper"); + System.load(lib); + } + + @Override + public synchronized void savePassword(String url, String username, char[] password) { + byte[] pwBytes = null; + boolean success = false; + try { + String desc = DESC_PREFIX + username + "@" + url; + if (password == null) { + pwBytes = new byte[]{}; + } else { + pwBytes = Charset.defaultCharset().encode(CharBuffer.wrap(password)).array(); + } + success = gnomeKeyringWrapperSavePasswordNative(url, username, pwBytes, desc); + } finally { + if (pwBytes != null) { + Arrays.fill(pwBytes, (byte) 0); + } + } + if (!success) { + throw new KeyringException("Couldn't save password."); + } + } + + @Override + public synchronized char[] getPassword(String url, String username) { + byte[] pwBytes = gnomeKeyringWrapperGetPasswordNative(url, username); + char[] password = null; + if (pwBytes != null) { + try { + password = Charset.defaultCharset().decode(ByteBuffer.wrap(pwBytes)).array(); + } finally { + Arrays.fill(pwBytes, (byte) 0); + } + } + return password; + } + + @Override + public synchronized void clearPassword(String url, String username) { + if (!gnomeKeyringWrapperClearPasswordNative(url, username)) { + throw new RuntimeException("Couldn't clear password."); + } + + } + + private static native boolean gnomeKeyringWrapperSavePasswordNative(String url, String userName, byte[] password, String description); + private static native byte[] gnomeKeyringWrapperGetPasswordNative(String url, String userName); + private static native boolean gnomeKeyringWrapperClearPasswordNative(String url, String userName); +} +
--- a/keyring/src/main/native/libgnome-keyring/GnomeKeyringLibraryNative.c Wed Apr 06 14:52:26 2016 +0200 +++ b/keyring/src/main/native/libgnome-keyring/GnomeKeyringLibraryNative.c Fri Apr 08 13:18:48 2016 +0200 @@ -34,7 +34,7 @@ * to do so, delete this exception statement from your version. */ -#include "com_redhat_thermostat_utils_keyring_impl_KeyringImpl.h" +#include "com_redhat_thermostat_utils_keyring_internal_KeyringImpl.h" #include <jni.h> #include <glib.h> @@ -58,7 +58,7 @@ } JNIEXPORT jboolean JNICALL -Java_com_redhat_thermostat_utils_keyring_impl_KeyringImpl_gnomeKeyringWrapperSavePasswordNative +Java_com_redhat_thermostat_utils_keyring_internal_KeyringImpl_gnomeKeyringWrapperSavePasswordNative (JNIEnv *env, jclass GnomeKeyringLibraryNativeClass, jstring jurl, jstring juserName, jbyteArray jpassword, jstring jdescription) { int passIndex; @@ -133,7 +133,7 @@ } JNIEXPORT jbyteArray JNICALL -Java_com_redhat_thermostat_utils_keyring_impl_KeyringImpl_gnomeKeyringWrapperGetPasswordNative +Java_com_redhat_thermostat_utils_keyring_internal_KeyringImpl_gnomeKeyringWrapperGetPasswordNative (JNIEnv *env, jclass GnomeKeyringLibraryNative, jstring jurl, jstring juserName) { const char *url = (*env)->GetStringUTFChars(env, jurl, NULL); @@ -175,7 +175,7 @@ } JNIEXPORT jboolean JNICALL -Java_com_redhat_thermostat_utils_keyring_impl_KeyringImpl_gnomeKeyringWrapperClearPasswordNative +Java_com_redhat_thermostat_utils_keyring_internal_KeyringImpl_gnomeKeyringWrapperClearPasswordNative (JNIEnv *env, jclass GnomeKeyringLibraryNative, jstring jurl, jstring juserName) { const char *url = (*env)->GetStringUTFChars(env, jurl, NULL);
--- a/keyring/src/main/native/libgnome-keyring/Makefile Wed Apr 06 14:52:26 2016 +0200 +++ b/keyring/src/main/native/libgnome-keyring/Makefile Fri Apr 08 13:18:48 2016 +0200 @@ -18,7 +18,7 @@ MYLDFLAGS += `pkg-config --libs gnome-keyring-1` .PHONY: -JNI_LIST = com.redhat.thermostat.utils.keyring.impl.KeyringImpl +JNI_LIST = com.redhat.thermostat.utils.keyring.internal.KeyringImpl $(JNI_LIST): $(JAVAH) -force -classpath $(CLASSPATH) -d $(TARGET_DIR) $(JNI_LIST)
--- a/keyring/src/main/native/libsecret/LibsecretKeyringLibraryNative.c Wed Apr 06 14:52:26 2016 +0200 +++ b/keyring/src/main/native/libsecret/LibsecretKeyringLibraryNative.c Fri Apr 08 13:18:48 2016 +0200 @@ -34,7 +34,7 @@ * to do so, delete this exception statement from your version. */ -#include "com_redhat_thermostat_utils_keyring_impl_KeyringImpl.h" +#include "com_redhat_thermostat_utils_keyring_internal_KeyringImpl.h" #include <jni.h> #include <glib.h> @@ -58,7 +58,7 @@ } JNIEXPORT jboolean JNICALL -Java_com_redhat_thermostat_utils_keyring_impl_KeyringImpl_gnomeKeyringWrapperSavePasswordNative +Java_com_redhat_thermostat_utils_keyring_internal_KeyringImpl_gnomeKeyringWrapperSavePasswordNative (JNIEnv *env, jclass GnomeKeyringLibraryNativeClass, jstring jurl, jstring juserName, jbyteArray jpassword, jstring jdescription) { int passIndex; @@ -141,7 +141,7 @@ } JNIEXPORT jbyteArray JNICALL -Java_com_redhat_thermostat_utils_keyring_impl_KeyringImpl_gnomeKeyringWrapperGetPasswordNative +Java_com_redhat_thermostat_utils_keyring_internal_KeyringImpl_gnomeKeyringWrapperGetPasswordNative (JNIEnv *env, jclass GnomeKeyringLibraryNative, jstring jurl, jstring juserName) { const char *url = (*env)->GetStringUTFChars(env, jurl, NULL); @@ -188,7 +188,7 @@ } JNIEXPORT jboolean JNICALL -Java_com_redhat_thermostat_utils_keyring_impl_KeyringImpl_gnomeKeyringWrapperClearPasswordNative +Java_com_redhat_thermostat_utils_keyring_internal_KeyringImpl_gnomeKeyringWrapperClearPasswordNative (JNIEnv *env, jclass GnomeKeyringLibraryNative, jstring jurl, jstring juserName) { const char *url = (*env)->GetStringUTFChars(env, jurl, NULL);
--- a/keyring/src/main/native/libsecret/Makefile Wed Apr 06 14:52:26 2016 +0200 +++ b/keyring/src/main/native/libsecret/Makefile Fri Apr 08 13:18:48 2016 +0200 @@ -18,7 +18,7 @@ MYLDFLAGS += `pkg-config --libs libsecret-1` .PHONY: -JNI_LIST = com.redhat.thermostat.utils.keyring.impl.KeyringImpl +JNI_LIST = com.redhat.thermostat.utils.keyring.internal.KeyringImpl $(JNI_LIST): $(JAVAH) -force -classpath $(CLASSPATH) -d $(TARGET_DIR) $(JNI_LIST)
--- a/keyring/src/test/java/com/redhat/thermostat/utils/keyring/impl/KeyringImplTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -/* - * Copyright 2012-2016 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.utils.keyring.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -import org.junit.Ignore; -import org.junit.Test; - -public class KeyringImplTest { - - @Ignore // FIXME Hangs waiting for user to unlock keyring. - @Test - public void verifySavedPasswordIsRetrieveable() { - String url = "www.example1.com"; - String user = "mike"; - char[] pw = new char[] {'1', '2', '3'}; - KeyringImpl k = new KeyringImpl(); - k.savePassword(url, user, pw); - assertEquals(new String(pw), new String(k.getPassword(url, user))); - - // Cleanup - k.clearPassword(url, user); - } - - @Ignore // FIXME Hangs waiting for user to unlock keyring. - @Test - public void verifySavePasswordReplacesExisting() { - String url = "www.example2.com"; - String user = "mike"; - char[] pw1 = new char[] {'1', '2', '3'}; - char[] pw2 = new char[] {'4', '5', '6'}; - KeyringImpl k = new KeyringImpl(); - k.savePassword(url, user, pw1); - k.savePassword(url, user, pw2); - - assertEquals(new String(pw2), new String(k.getPassword(url, user))); - - // Cleanup - k.clearPassword(url, user); - } - - @Ignore // FIXME Hangs waiting for user to unlock keyring. - @Test - public void verifyClearedPasswordIsCleared() { - String url = "www.example3.com"; - String user = "mike"; - char[] pw = new char[] {'1', '2', '3'}; - KeyringImpl k = new KeyringImpl(); - k.savePassword(url, user, pw); - assertNotNull(k.getPassword(url, user)); - k.clearPassword(url, user); - assertNull(k.getPassword(url, user)); - } - - @Ignore // FIXME Hangs waiting for user to unlock keyring. - @Test - public void multipleServersSameUser() { - String url1 = "www.example4.com"; - String url2 = "www.fake.com"; - String user = "mike"; - char[] pw1 = new char[] {'1', '2', '3'}; - char[] pw2 = new char[] {'4', '5', '6'}; - KeyringImpl k = new KeyringImpl(); - k.savePassword(url1, user, pw1); - k.savePassword(url2, user, pw2); - - assertEquals(new String(pw1), new String(k.getPassword(url1, user))); - assertEquals(new String(pw2), new String(k.getPassword(url2, user))); - - // Cleanup - k.clearPassword(url1, user); - k.clearPassword(url2, user); - } - - @Ignore // FIXME Hangs waiting for user to unlock keyring. - @Test - public void multipleUsersSameServer() { - String url = "www.example5.com"; - String user1 = "mike"; - String user2 = "mary"; - char[] pw1 = new char[] {'1', '2', '3'}; - char[] pw2 = new char[] {'4', '5', '6'}; - KeyringImpl k = new KeyringImpl(); - k.savePassword(url, user1, pw1); - k.savePassword(url, user2, pw2); - - assertEquals(new String(pw1), new String(k.getPassword(url, user1))); - assertEquals(new String(pw2), new String(k.getPassword(url, user2))); - - // Cleanup - k.clearPassword(url, user1); - k.clearPassword(url, user2); - } - -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/keyring/src/test/java/com/redhat/thermostat/utils/keyring/internal/KeyringImplTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,133 @@ +/* + * Copyright 2012-2016 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.utils.keyring.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import org.junit.Ignore; +import org.junit.Test; + +public class KeyringImplTest { + + @Ignore // FIXME Hangs waiting for user to unlock keyring. + @Test + public void verifySavedPasswordIsRetrieveable() { + String url = "www.example1.com"; + String user = "mike"; + char[] pw = new char[] {'1', '2', '3'}; + KeyringImpl k = new KeyringImpl(); + k.savePassword(url, user, pw); + assertEquals(new String(pw), new String(k.getPassword(url, user))); + + // Cleanup + k.clearPassword(url, user); + } + + @Ignore // FIXME Hangs waiting for user to unlock keyring. + @Test + public void verifySavePasswordReplacesExisting() { + String url = "www.example2.com"; + String user = "mike"; + char[] pw1 = new char[] {'1', '2', '3'}; + char[] pw2 = new char[] {'4', '5', '6'}; + KeyringImpl k = new KeyringImpl(); + k.savePassword(url, user, pw1); + k.savePassword(url, user, pw2); + + assertEquals(new String(pw2), new String(k.getPassword(url, user))); + + // Cleanup + k.clearPassword(url, user); + } + + @Ignore // FIXME Hangs waiting for user to unlock keyring. + @Test + public void verifyClearedPasswordIsCleared() { + String url = "www.example3.com"; + String user = "mike"; + char[] pw = new char[] {'1', '2', '3'}; + KeyringImpl k = new KeyringImpl(); + k.savePassword(url, user, pw); + assertNotNull(k.getPassword(url, user)); + k.clearPassword(url, user); + assertNull(k.getPassword(url, user)); + } + + @Ignore // FIXME Hangs waiting for user to unlock keyring. + @Test + public void multipleServersSameUser() { + String url1 = "www.example4.com"; + String url2 = "www.fake.com"; + String user = "mike"; + char[] pw1 = new char[] {'1', '2', '3'}; + char[] pw2 = new char[] {'4', '5', '6'}; + KeyringImpl k = new KeyringImpl(); + k.savePassword(url1, user, pw1); + k.savePassword(url2, user, pw2); + + assertEquals(new String(pw1), new String(k.getPassword(url1, user))); + assertEquals(new String(pw2), new String(k.getPassword(url2, user))); + + // Cleanup + k.clearPassword(url1, user); + k.clearPassword(url2, user); + } + + @Ignore // FIXME Hangs waiting for user to unlock keyring. + @Test + public void multipleUsersSameServer() { + String url = "www.example5.com"; + String user1 = "mike"; + String user2 = "mary"; + char[] pw1 = new char[] {'1', '2', '3'}; + char[] pw2 = new char[] {'4', '5', '6'}; + KeyringImpl k = new KeyringImpl(); + k.savePassword(url, user1, pw1); + k.savePassword(url, user2, pw2); + + assertEquals(new String(pw1), new String(k.getPassword(url, user1))); + assertEquals(new String(pw2), new String(k.getPassword(url, user2))); + + // Cleanup + k.clearPassword(url, user1); + k.clearPassword(url, user2); + } + +} +
--- a/main/pom.xml Wed Apr 06 14:52:26 2016 +0200 +++ b/main/pom.xml Fri Apr 08 13:18:48 2016 +0200 @@ -127,7 +127,7 @@ com.redhat.thermostat.main, </Export-Package> <Private-Package> - com.redhat.thermostat.main.impl + com.redhat.thermostat.main.internal </Private-Package> <!-- Do not autogenerate uses clauses in Manifests --> <_nouses>true</_nouses>
--- a/main/src/main/java/com/redhat/thermostat/main/Thermostat.java Wed Apr 06 14:52:26 2016 +0200 +++ b/main/src/main/java/com/redhat/thermostat/main/Thermostat.java Fri Apr 08 13:18:48 2016 +0200 @@ -36,8 +36,8 @@ package com.redhat.thermostat.main; -import com.redhat.thermostat.main.impl.FrameworkOptionsProcessor; -import com.redhat.thermostat.main.impl.FrameworkProvider; +import com.redhat.thermostat.main.internal.FrameworkOptionsProcessor; +import com.redhat.thermostat.main.internal.FrameworkProvider; import com.redhat.thermostat.shared.config.CommonPaths; import com.redhat.thermostat.shared.config.internal.CommonPathsImpl;
--- a/main/src/main/java/com/redhat/thermostat/main/impl/FrameworkOptionsProcessor.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -/* - * Copyright 2012-2016 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.main.impl; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import com.redhat.thermostat.launcher.FrameworkOptions; - -/** - * Thermostat options for the OSGi framework and relevant debug output. - * - */ -public class FrameworkOptionsProcessor { - - private final Map<FrameworkOptions, String> globalOptions; - private final String[] otherOptions; - - public FrameworkOptionsProcessor(String[] args) { - this.globalOptions = new HashMap<>(); - initializeDefaultGlobalOptions(); - this.otherOptions = processGlobalOptions(args); - } - - private void initializeDefaultGlobalOptions() { - // set up default boot delegation to allow the vm-profiler to work - // correctly by default - globalOptions.put(FrameworkOptions.BOOT_DELEGATION, - "com.redhat.thermostat.vm.profiler.agent.jvm," + - "com.redhat.thermostat.vm.profiler.agent.asm," + - "com.redhat.thermostat.vm.profiler.agent.asm.commons"); - } - - private String[] processGlobalOptions(String[] args) { - List<String> toProcess = new ArrayList<>(Arrays.asList(args)); - Iterator<String> iter = toProcess.iterator(); - while (iter.hasNext()) { - String arg = iter.next(); - if (FrameworkOptions.PRINT_OSGI_INFO.getOptString().equals(arg)) { - globalOptions.put(FrameworkOptions.PRINT_OSGI_INFO, - Boolean.TRUE.toString()); - iter.remove(); - } - if (FrameworkOptions.IGNORE_BUNDLE_VERSIONS.getOptString().equals(arg)) { - globalOptions.put(FrameworkOptions.IGNORE_BUNDLE_VERSIONS, - Boolean.TRUE.toString()); - iter.remove(); - } - if (arg.startsWith(FrameworkOptions.BOOT_DELEGATION.getOptString() + "=")) { - int startIndex = (FrameworkOptions.BOOT_DELEGATION.getOptString() + "=") - .length(); - String bootDelegation = arg.substring(startIndex); - if ("".equals(bootDelegation)) { - throw new RuntimeException( - "Unexpected string used with boot delegation: '" - + bootDelegation + "'"); - } - globalOptions.put(FrameworkOptions.BOOT_DELEGATION, bootDelegation); - iter.remove(); - } - } - return toProcess.toArray(new String[] {}); - } - - public String[] getOtherOptions() { - return otherOptions; - } - - public boolean printOsgiInfo() { - return globalOptions.containsKey(FrameworkOptions.PRINT_OSGI_INFO); - } - - public boolean ignoreBundleVersions() { - return globalOptions.containsKey(FrameworkOptions.IGNORE_BUNDLE_VERSIONS); - } - - public String bootDelegationValue() { - return globalOptions.get(FrameworkOptions.BOOT_DELEGATION); - } - -}
--- a/main/src/main/java/com/redhat/thermostat/main/impl/FrameworkProvider.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,311 +0,0 @@ -/* - * Copyright 2012-2016 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.main.impl; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Method; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.ServiceLoader; - -import org.osgi.framework.BundleException; -import org.osgi.framework.Constants; -import org.osgi.framework.launch.Framework; -import org.osgi.framework.launch.FrameworkFactory; -import org.osgi.util.tracker.ServiceTracker; - -import com.redhat.thermostat.launcher.BundleManager; -import com.redhat.thermostat.launcher.Launcher; -import com.redhat.thermostat.shared.config.CommonPaths; - -public class FrameworkProvider { - - private static final String DEBUG_PREFIX = "FrameworkProvider: "; - private static final String PROPS_FILE = "/com/redhat/thermostat/main/impl/bootstrapbundles.properties"; - private static final String BUNDLELIST = "bundles"; - - private final CommonPaths paths; - private final FrameworkOptionsProcessor frameworkOptionsProcessor; - - // The framework cache location; Must not be shared between apps! - private Path osgiCacheStorage; - - - public FrameworkProvider(CommonPaths paths, FrameworkOptionsProcessor options) { - this.paths = paths; - this.frameworkOptionsProcessor = options; - } - - // This is our ticket into OSGi land. Unfortunately, we to use a bit of reflection here. - // The launcher and bundleloader are instantiated from within their bundles, ie loaded - // by the bundle classloader. - public void start(String[] args) { - try { - Framework framework = makeFramework(); - prepareFramework(framework); - loadBootstrapBundles(framework); - setLoaderVerbosity(framework); - setIgnoreBundleVersions(framework); - runLauncher(framework, args); - } catch (InterruptedException | BundleException | IOException e) { - throw new RuntimeException("Could not start framework.", e); - } - } - - private String getOSGiPublicPackages() throws FileNotFoundException, IOException { - File osgiBundleDefinitions = new File(paths.getSystemConfigurationDirectory(), "osgi-export.properties"); - - Properties bundles = new Properties(); - bundles.load(new FileInputStream(osgiBundleDefinitions)); - - StringBuilder publicPackages = new StringBuilder(); - /* - * Packages the launcher requires - */ - //publicPackages.append("com.redhat.thermostat.common.services"); - boolean firstPackage = true; - for (Object bundle : bundles.keySet()) { - if (!firstPackage) { - publicPackages.append(",\n"); - } - firstPackage = false; - publicPackages.append(bundle); - String bundleVersion = (String) bundles.get(bundle); - if (!bundleVersion.isEmpty()) { - publicPackages.append("; version=").append(bundleVersion); - } - } - - return publicPackages.toString(); - } - - private void prepareFramework(final Framework framework) throws BundleException, IOException { - framework.init(); - framework.start(); - if (frameworkOptionsProcessor.printOsgiInfo()) { - System.out.println(DEBUG_PREFIX + "OSGi framework has started."); - } - - Runtime.getRuntime().addShutdownHook(new Thread() { - @Override - public void run() { - try { - framework.stop(); - framework.waitForStop(0); - if (frameworkOptionsProcessor.printOsgiInfo()) { - System.out.println(DEBUG_PREFIX + "OSGi framework has shut down."); - } - recursivelyDeleteDirectory(osgiCacheStorage.toFile()); - if (frameworkOptionsProcessor.printOsgiInfo()) { - System.out.println(DEBUG_PREFIX + "Removed OSGi cache directory: " - + osgiCacheStorage.toFile().getAbsolutePath()); - } - } catch (Exception e) { - throw new RuntimeException("Error shutting down framework.", e); - } - } - }); - - } - - private void recursivelyDeleteDirectory(File directory) { - for (File file: directory.listFiles()) { - if (file.isDirectory()) { - recursivelyDeleteDirectory(file); - } - file.delete(); - } - directory.delete(); - } - - - private Framework makeFramework() throws FileNotFoundException, IOException { - File osgiCacheDir = new File(paths.getUserCacheDirectory(), "osgi-cache"); - if (!osgiCacheDir.isDirectory() && !osgiCacheDir.mkdirs()) { - throw new RuntimeException("Unable to create " + osgiCacheDir); - } - - // Create temporary directory which will be used as cache for OSGi bundles. See - // http://www.osgi.org/javadoc/r4v43/core/org/osgi/framework/Constants.html#FRAMEWORK_STORAGE - // for details about what this location is used for. - // - // Agent, swing gui client application must not use the same location as this tricks the framework - // into thinking that some bundles are installed and loaded when that might not actually be the case. - // Note that we do not specify the org.osgi.framework.storage.clean property and the default is to NOT - // clean the cache, which is when we might run into trouble if this location is shared. This - // temp directory will be deleted on VM shutdown. - // - // This fixes Thermostat BZ 1110. - osgiCacheStorage = Files.createTempDirectory(osgiCacheDir.toPath(), null); - if (frameworkOptionsProcessor.printOsgiInfo()) { - System.out.println(DEBUG_PREFIX + "OSGi cache location: " - + osgiCacheStorage.toFile().getAbsolutePath()); - } - - ServiceLoader<FrameworkFactory> loader = ServiceLoader.load(FrameworkFactory.class, - getClass().getClassLoader()); - Map<String, String> bundleConfigurations = new HashMap<String, String>(); - String extraPackages = getOSGiPublicPackages(); - bundleConfigurations.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, extraPackages); - bundleConfigurations.put(Constants.FRAMEWORK_STORAGE, osgiCacheStorage.toFile().getAbsolutePath()); - if (frameworkOptionsProcessor.bootDelegationValue() != null) { - if (frameworkOptionsProcessor.printOsgiInfo()) { - System.out.println("Boot delegation: " + frameworkOptionsProcessor.bootDelegationValue()); - } - bundleConfigurations.put(Constants.FRAMEWORK_BOOTDELEGATION, frameworkOptionsProcessor.bootDelegationValue()); - } - Iterator<FrameworkFactory> factories = loader.iterator(); - if (factories.hasNext()) { - // we just want the first found - return factories.next().newFramework(bundleConfigurations); - } else { - throw new InternalError("ServiceLoader cannot find a FrameworkFactory!"); - } - } - - private void loadBootstrapBundles(Framework framework) throws BundleException, InterruptedException { - Properties bootstrapProps = new Properties(); - // the properties file should be in the same package as this class - InputStream res = getClass().getResourceAsStream(PROPS_FILE); - if (res != null) { - try { - bootstrapProps.load(res); - } catch (IOException e) { - throw new RuntimeException("Could not load bootstrap bundle properties.", e); - } - } - String[] bundles = bootstrapProps.getProperty(BUNDLELIST).split(","); - List<String> locations = new ArrayList<>(); - for (String bundle : bundles) { - String trimmed = bundle.trim(); - if (trimmed != null && trimmed.length() > 0) { - String location = actualLocation(trimmed); - locations.add(location); - } - } - BundleManager.preLoadBundles(framework, locations, frameworkOptionsProcessor.printOsgiInfo()); - } - - private void setLoaderVerbosity(Framework framework) throws InterruptedException { - Object loader = getService(framework, BundleManager.class.getName()); - callVoidReflectedMethod(loader, "setPrintOSGiInfo", frameworkOptionsProcessor.printOsgiInfo()); - } - - private void setIgnoreBundleVersions(Framework framework) throws InterruptedException { - Object loader = getService(framework, BundleManager.class.getName()); - callVoidReflectedMethod(loader, "setIgnoreBundleVersions", frameworkOptionsProcessor.ignoreBundleVersions()); - } - - private void runLauncher(Framework framework, String[] args) throws InterruptedException { - Object launcher = getService(framework, Launcher.class.getName()); - callVoidReflectedMethod(launcher, "run", args, false); - } - - private Object getService(Framework framework, String name) throws InterruptedException { - Object service = null; - @SuppressWarnings({ "unchecked", "rawtypes" }) - ServiceTracker tracker = new ServiceTracker(framework.getBundleContext(), name, null); - tracker.open(); - service = tracker.waitForService(0); - tracker.close(); - return service; - } - - /** - * Call {@code object}.{@code name} with {@code args} as the arguments. The - * return value is ignored. The types of the method arguments must exactly - * match the types of the supplied arguments, but primitives are used unboxed. - */ - private void callVoidReflectedMethod(Object object, String name, Object... args) { - Class<?> clazz = object.getClass(); - Class<?>[] classes = new Class<?>[args.length]; - for (int i = 0; i < args.length; i++) { - classes[i] = preferPrimitiveClass(args[i].getClass()); - } - - try { - Method m = clazz.getMethod(name, classes); - m.invoke(object, args); - } catch (ReflectiveOperationException e) { - throw new AssertionError("Unable to call '" + name + "' method on object " + object, e); - } - } - - private static <T> Class<T> preferPrimitiveClass(Class<T> boxedPrimitive) { - HashMap<Class<?>, Class<?>> map = new HashMap<>(); - map.put(Byte.class, byte.class); - map.put(Short.class, short.class); - map.put(Integer.class, int.class); - map.put(Long.class, long.class); - map.put(Float.class, float.class); - map.put(Double.class, double.class); - map.put(Boolean.class, boolean.class); - map.put(Character.class, char.class); - - if (map.containsKey(boxedPrimitive)) { - return (Class<T>) map.get(boxedPrimitive); - } else { - return boxedPrimitive; - } - } - - // Resolve symlinks completely; This makes the behaviour of this class - // consistent with BundleManagerImpl and avoid problems where two different - // files across bootstrap and later code provide the same bundle symbolic - // name version - private String actualLocation(String resourceName) { - File file = new File(paths.getSystemLibRoot(), resourceName); - try { - return file.getCanonicalFile().toURI().toString(); - } catch (IOException e) { - // okay, lets not canonicalize the path - return file.toURI().toString(); - } - } - -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/src/main/java/com/redhat/thermostat/main/internal/FrameworkOptionsProcessor.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,119 @@ +/* + * Copyright 2012-2016 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.main.internal; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import com.redhat.thermostat.launcher.FrameworkOptions; + +/** + * Thermostat options for the OSGi framework and relevant debug output. + * + */ +public class FrameworkOptionsProcessor { + + private final Map<FrameworkOptions, String> globalOptions; + private final String[] otherOptions; + + public FrameworkOptionsProcessor(String[] args) { + this.globalOptions = new HashMap<>(); + initializeDefaultGlobalOptions(); + this.otherOptions = processGlobalOptions(args); + } + + private void initializeDefaultGlobalOptions() { + // set up default boot delegation to allow the vm-profiler to work + // correctly by default + globalOptions.put(FrameworkOptions.BOOT_DELEGATION, + "com.redhat.thermostat.vm.profiler.agent.jvm," + + "com.redhat.thermostat.vm.profiler.agent.asm," + + "com.redhat.thermostat.vm.profiler.agent.asm.commons"); + } + + private String[] processGlobalOptions(String[] args) { + List<String> toProcess = new ArrayList<>(Arrays.asList(args)); + Iterator<String> iter = toProcess.iterator(); + while (iter.hasNext()) { + String arg = iter.next(); + if (FrameworkOptions.PRINT_OSGI_INFO.getOptString().equals(arg)) { + globalOptions.put(FrameworkOptions.PRINT_OSGI_INFO, + Boolean.TRUE.toString()); + iter.remove(); + } + if (FrameworkOptions.IGNORE_BUNDLE_VERSIONS.getOptString().equals(arg)) { + globalOptions.put(FrameworkOptions.IGNORE_BUNDLE_VERSIONS, + Boolean.TRUE.toString()); + iter.remove(); + } + if (arg.startsWith(FrameworkOptions.BOOT_DELEGATION.getOptString() + "=")) { + int startIndex = (FrameworkOptions.BOOT_DELEGATION.getOptString() + "=") + .length(); + String bootDelegation = arg.substring(startIndex); + if ("".equals(bootDelegation)) { + throw new RuntimeException( + "Unexpected string used with boot delegation: '" + + bootDelegation + "'"); + } + globalOptions.put(FrameworkOptions.BOOT_DELEGATION, bootDelegation); + iter.remove(); + } + } + return toProcess.toArray(new String[] {}); + } + + public String[] getOtherOptions() { + return otherOptions; + } + + public boolean printOsgiInfo() { + return globalOptions.containsKey(FrameworkOptions.PRINT_OSGI_INFO); + } + + public boolean ignoreBundleVersions() { + return globalOptions.containsKey(FrameworkOptions.IGNORE_BUNDLE_VERSIONS); + } + + public String bootDelegationValue() { + return globalOptions.get(FrameworkOptions.BOOT_DELEGATION); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/src/main/java/com/redhat/thermostat/main/internal/FrameworkProvider.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,311 @@ +/* + * Copyright 2012-2016 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.main.internal; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.ServiceLoader; + +import org.osgi.framework.BundleException; +import org.osgi.framework.Constants; +import org.osgi.framework.launch.Framework; +import org.osgi.framework.launch.FrameworkFactory; +import org.osgi.util.tracker.ServiceTracker; + +import com.redhat.thermostat.launcher.BundleManager; +import com.redhat.thermostat.launcher.Launcher; +import com.redhat.thermostat.shared.config.CommonPaths; + +public class FrameworkProvider { + + private static final String DEBUG_PREFIX = "FrameworkProvider: "; + private static final String PROPS_FILE = "/com/redhat/thermostat/main/internal/bootstrapbundles.properties"; + private static final String BUNDLELIST = "bundles"; + + private final CommonPaths paths; + private final FrameworkOptionsProcessor frameworkOptionsProcessor; + + // The framework cache location; Must not be shared between apps! + private Path osgiCacheStorage; + + + public FrameworkProvider(CommonPaths paths, FrameworkOptionsProcessor options) { + this.paths = paths; + this.frameworkOptionsProcessor = options; + } + + // This is our ticket into OSGi land. Unfortunately, we to use a bit of reflection here. + // The launcher and bundleloader are instantiated from within their bundles, ie loaded + // by the bundle classloader. + public void start(String[] args) { + try { + Framework framework = makeFramework(); + prepareFramework(framework); + loadBootstrapBundles(framework); + setLoaderVerbosity(framework); + setIgnoreBundleVersions(framework); + runLauncher(framework, args); + } catch (InterruptedException | BundleException | IOException e) { + throw new RuntimeException("Could not start framework.", e); + } + } + + private String getOSGiPublicPackages() throws FileNotFoundException, IOException { + File osgiBundleDefinitions = new File(paths.getSystemConfigurationDirectory(), "osgi-export.properties"); + + Properties bundles = new Properties(); + bundles.load(new FileInputStream(osgiBundleDefinitions)); + + StringBuilder publicPackages = new StringBuilder(); + /* + * Packages the launcher requires + */ + //publicPackages.append("com.redhat.thermostat.common.services"); + boolean firstPackage = true; + for (Object bundle : bundles.keySet()) { + if (!firstPackage) { + publicPackages.append(",\n"); + } + firstPackage = false; + publicPackages.append(bundle); + String bundleVersion = (String) bundles.get(bundle); + if (!bundleVersion.isEmpty()) { + publicPackages.append("; version=").append(bundleVersion); + } + } + + return publicPackages.toString(); + } + + private void prepareFramework(final Framework framework) throws BundleException, IOException { + framework.init(); + framework.start(); + if (frameworkOptionsProcessor.printOsgiInfo()) { + System.out.println(DEBUG_PREFIX + "OSGi framework has started."); + } + + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + try { + framework.stop(); + framework.waitForStop(0); + if (frameworkOptionsProcessor.printOsgiInfo()) { + System.out.println(DEBUG_PREFIX + "OSGi framework has shut down."); + } + recursivelyDeleteDirectory(osgiCacheStorage.toFile()); + if (frameworkOptionsProcessor.printOsgiInfo()) { + System.out.println(DEBUG_PREFIX + "Removed OSGi cache directory: " + + osgiCacheStorage.toFile().getAbsolutePath()); + } + } catch (Exception e) { + throw new RuntimeException("Error shutting down framework.", e); + } + } + }); + + } + + private void recursivelyDeleteDirectory(File directory) { + for (File file: directory.listFiles()) { + if (file.isDirectory()) { + recursivelyDeleteDirectory(file); + } + file.delete(); + } + directory.delete(); + } + + + private Framework makeFramework() throws FileNotFoundException, IOException { + File osgiCacheDir = new File(paths.getUserCacheDirectory(), "osgi-cache"); + if (!osgiCacheDir.isDirectory() && !osgiCacheDir.mkdirs()) { + throw new RuntimeException("Unable to create " + osgiCacheDir); + } + + // Create temporary directory which will be used as cache for OSGi bundles. See + // http://www.osgi.org/javadoc/r4v43/core/org/osgi/framework/Constants.html#FRAMEWORK_STORAGE + // for details about what this location is used for. + // + // Agent, swing gui client application must not use the same location as this tricks the framework + // into thinking that some bundles are installed and loaded when that might not actually be the case. + // Note that we do not specify the org.osgi.framework.storage.clean property and the default is to NOT + // clean the cache, which is when we might run into trouble if this location is shared. This + // temp directory will be deleted on VM shutdown. + // + // This fixes Thermostat BZ 1110. + osgiCacheStorage = Files.createTempDirectory(osgiCacheDir.toPath(), null); + if (frameworkOptionsProcessor.printOsgiInfo()) { + System.out.println(DEBUG_PREFIX + "OSGi cache location: " + + osgiCacheStorage.toFile().getAbsolutePath()); + } + + ServiceLoader<FrameworkFactory> loader = ServiceLoader.load(FrameworkFactory.class, + getClass().getClassLoader()); + Map<String, String> bundleConfigurations = new HashMap<String, String>(); + String extraPackages = getOSGiPublicPackages(); + bundleConfigurations.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, extraPackages); + bundleConfigurations.put(Constants.FRAMEWORK_STORAGE, osgiCacheStorage.toFile().getAbsolutePath()); + if (frameworkOptionsProcessor.bootDelegationValue() != null) { + if (frameworkOptionsProcessor.printOsgiInfo()) { + System.out.println("Boot delegation: " + frameworkOptionsProcessor.bootDelegationValue()); + } + bundleConfigurations.put(Constants.FRAMEWORK_BOOTDELEGATION, frameworkOptionsProcessor.bootDelegationValue()); + } + Iterator<FrameworkFactory> factories = loader.iterator(); + if (factories.hasNext()) { + // we just want the first found + return factories.next().newFramework(bundleConfigurations); + } else { + throw new InternalError("ServiceLoader cannot find a FrameworkFactory!"); + } + } + + private void loadBootstrapBundles(Framework framework) throws BundleException, InterruptedException { + Properties bootstrapProps = new Properties(); + // the properties file should be in the same package as this class + InputStream res = getClass().getResourceAsStream(PROPS_FILE); + if (res != null) { + try { + bootstrapProps.load(res); + } catch (IOException e) { + throw new RuntimeException("Could not load bootstrap bundle properties.", e); + } + } + String[] bundles = bootstrapProps.getProperty(BUNDLELIST).split(","); + List<String> locations = new ArrayList<>(); + for (String bundle : bundles) { + String trimmed = bundle.trim(); + if (trimmed != null && trimmed.length() > 0) { + String location = actualLocation(trimmed); + locations.add(location); + } + } + BundleManager.preLoadBundles(framework, locations, frameworkOptionsProcessor.printOsgiInfo()); + } + + private void setLoaderVerbosity(Framework framework) throws InterruptedException { + Object loader = getService(framework, BundleManager.class.getName()); + callVoidReflectedMethod(loader, "setPrintOSGiInfo", frameworkOptionsProcessor.printOsgiInfo()); + } + + private void setIgnoreBundleVersions(Framework framework) throws InterruptedException { + Object loader = getService(framework, BundleManager.class.getName()); + callVoidReflectedMethod(loader, "setIgnoreBundleVersions", frameworkOptionsProcessor.ignoreBundleVersions()); + } + + private void runLauncher(Framework framework, String[] args) throws InterruptedException { + Object launcher = getService(framework, Launcher.class.getName()); + callVoidReflectedMethod(launcher, "run", args, false); + } + + private Object getService(Framework framework, String name) throws InterruptedException { + Object service = null; + @SuppressWarnings({ "unchecked", "rawtypes" }) + ServiceTracker tracker = new ServiceTracker(framework.getBundleContext(), name, null); + tracker.open(); + service = tracker.waitForService(0); + tracker.close(); + return service; + } + + /** + * Call {@code object}.{@code name} with {@code args} as the arguments. The + * return value is ignored. The types of the method arguments must exactly + * match the types of the supplied arguments, but primitives are used unboxed. + */ + private void callVoidReflectedMethod(Object object, String name, Object... args) { + Class<?> clazz = object.getClass(); + Class<?>[] classes = new Class<?>[args.length]; + for (int i = 0; i < args.length; i++) { + classes[i] = preferPrimitiveClass(args[i].getClass()); + } + + try { + Method m = clazz.getMethod(name, classes); + m.invoke(object, args); + } catch (ReflectiveOperationException e) { + throw new AssertionError("Unable to call '" + name + "' method on object " + object, e); + } + } + + private static <T> Class<T> preferPrimitiveClass(Class<T> boxedPrimitive) { + HashMap<Class<?>, Class<?>> map = new HashMap<>(); + map.put(Byte.class, byte.class); + map.put(Short.class, short.class); + map.put(Integer.class, int.class); + map.put(Long.class, long.class); + map.put(Float.class, float.class); + map.put(Double.class, double.class); + map.put(Boolean.class, boolean.class); + map.put(Character.class, char.class); + + if (map.containsKey(boxedPrimitive)) { + return (Class<T>) map.get(boxedPrimitive); + } else { + return boxedPrimitive; + } + } + + // Resolve symlinks completely; This makes the behaviour of this class + // consistent with BundleManagerImpl and avoid problems where two different + // files across bootstrap and later code provide the same bundle symbolic + // name version + private String actualLocation(String resourceName) { + File file = new File(paths.getSystemLibRoot(), resourceName); + try { + return file.getCanonicalFile().toURI().toString(); + } catch (IOException e) { + // okay, lets not canonicalize the path + return file.toURI().toString(); + } + } + +} +
--- a/main/src/main/resources/com/redhat/thermostat/main/impl/bootstrapbundles.properties Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -bundles=thermostat-shared-config-${project.version}.jar, \ - thermostat-keyring-${project.version}.jar, \ - thermostat-storage-core-${project.version}.jar, \ - thermostat-common-core-${project.version}.jar, \ - thermostat-plugin-validator-${project.version}.jar, \ - thermostat-launcher-${project.version}.jar, \ - jline-${jline.version}.jar, \ - commons-cli-${commons-cli.version}.jar, \ - org.apache.felix.scr-${felix.scr.version}.jar, \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/src/main/resources/com/redhat/thermostat/main/internal/bootstrapbundles.properties Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,9 @@ +bundles=thermostat-shared-config-${project.version}.jar, \ + thermostat-keyring-${project.version}.jar, \ + thermostat-storage-core-${project.version}.jar, \ + thermostat-common-core-${project.version}.jar, \ + thermostat-plugin-validator-${project.version}.jar, \ + thermostat-launcher-${project.version}.jar, \ + jline-${jline.version}.jar, \ + commons-cli-${commons-cli.version}.jar, \ + org.apache.felix.scr-${felix.scr.version}.jar, \
--- a/main/src/test/java/com/redhat/thermostat/main/ThermostatTest.java Wed Apr 06 14:52:26 2016 +0200 +++ b/main/src/test/java/com/redhat/thermostat/main/ThermostatTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -49,8 +49,8 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; -import com.redhat.thermostat.main.impl.FrameworkOptionsProcessor; -import com.redhat.thermostat.main.impl.FrameworkProvider; +import com.redhat.thermostat.main.internal.FrameworkOptionsProcessor; +import com.redhat.thermostat.main.internal.FrameworkProvider; import com.redhat.thermostat.shared.config.CommonPaths; public class ThermostatTest {
--- a/main/src/test/java/com/redhat/thermostat/main/impl/FrameworkOptionsProcessorTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/* - * Copyright 2012-2016 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.main.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -import java.util.Arrays; - -import org.junit.Test; - -public class FrameworkOptionsProcessorTest { - - @Test - public void verifyDefaults() { - String[] args = new String[] { "help" }; - FrameworkOptionsProcessor opts = new FrameworkOptionsProcessor(args); - assertFalse(opts.printOsgiInfo()); - assertFalse(opts.ignoreBundleVersions()); - assertTrue(opts.bootDelegationValue().contains("com.redhat.thermostat.vm.profiler")); - assertEquals(Arrays.asList("help"), Arrays.asList(opts.getOtherOptions())); - } - - @Test - public void canGetPrintOsgiInfo() { - String[] args = new String[] { "--print-osgi-info", "help" }; - FrameworkOptionsProcessor opts = new FrameworkOptionsProcessor(args); - assertTrue(opts.printOsgiInfo()); - assertEquals(Arrays.asList("help"), - Arrays.asList(opts.getOtherOptions())); - } - - @Test - public void canGetBootDelegation() { - String[] args = new String[] { "--boot-delegation=foo", "help" }; - FrameworkOptionsProcessor opts = new FrameworkOptionsProcessor(args); - assertEquals("foo", opts.bootDelegationValue()); - assertEquals(Arrays.asList("help"), - Arrays.asList(opts.getOtherOptions())); - } - - @Test - public void canGetIgnoreBundleVersion() { - String[] args = new String[] { "--ignore-bundle-versions", "help" }; - FrameworkOptionsProcessor opts = new FrameworkOptionsProcessor(args); - assertTrue(opts.ignoreBundleVersions()); - assertEquals(Arrays.asList("help"), - Arrays.asList(opts.getOtherOptions())); - } - - @Test(expected = RuntimeException.class) - public void emtpyStringForBootDelegationThrowsException() { - String[] args = new String[] { "--boot-delegation=", "help" }; - // This is expected to fail since the boot delegation value is an empty - // string. - new FrameworkOptionsProcessor(args); - } -}
--- a/main/src/test/java/com/redhat/thermostat/main/impl/FrameworkProviderTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,272 +0,0 @@ -/* - * Copyright 2012-2016 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.main.impl; - -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.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.Collections; -import java.util.Hashtable; -import java.util.List; -import java.util.Map; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.BundleException; -import org.osgi.framework.Constants; -import org.osgi.framework.launch.Framework; -import org.osgi.util.tracker.ServiceTracker; -import org.osgi.util.tracker.ServiceTrackerCustomizer; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import com.redhat.thermostat.launcher.BundleInformation; -import com.redhat.thermostat.launcher.BundleManager; -import com.redhat.thermostat.launcher.Launcher; -import com.redhat.thermostat.shared.config.CommonPaths; -import com.redhat.thermostat.shared.config.internal.CommonPathsImpl; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({FrameworkProvider.class}) -public class FrameworkProviderTest { - - private static final String THERMOSTAT_HOME_PROPERTY = "THERMOSTAT_HOME"; - private static final String USER_THERMOSTAT_HOME_PROPERTY = "USER_THERMOSTAT_HOME"; - - private BundleContext mockContext; - - private Framework framework; - - private FakeBundleManager bundleManager; - private Launcher launcher; - private CommonPaths paths; - private String savedHome, savedUserHome; - - static class FakeBundleManager extends BundleManager /* extends BundleManagerImpl */ { - - private boolean printOSGiInfo; - private boolean ignoreBundleVersion; - - @Override - public void loadBundlesByName(List<BundleInformation> bundles) throws BundleException, IOException { - // do nothing - } - - @Override - public CommonPaths getCommonPaths() { - return null; - } - - // @Override - public void setPrintOSGiInfo(boolean print) { - this.printOSGiInfo = print; - } - - // @Override - public void setIgnoreBundleVersions(boolean ignore) { - this.ignoreBundleVersion = ignore; - } - - } - - @SuppressWarnings("rawtypes") - @Before - public void setUp() throws Exception { - Path tempDir; - tempDir = Files.createTempDirectory("FrameworkProviderTest"); - tempDir.toFile().deleteOnExit(); - savedHome = System.setProperty(THERMOSTAT_HOME_PROPERTY, tempDir.toString()); - savedUserHome = System.setProperty(USER_THERMOSTAT_HOME_PROPERTY, tempDir.toString()); - paths = new CommonPathsImpl(); - - File tempEtc = new File(tempDir.toFile(), "etc"); - tempEtc.mkdirs(); - tempEtc.deleteOnExit(); - - File tempProps = new File(tempEtc, "osgi-export.properties"); - tempProps.createNewFile(); - tempProps.deleteOnExit(); - - File tempBundleProps = new File(tempEtc, "bundles.properties"); - tempBundleProps.createNewFile(); - tempBundleProps.deleteOnExit(); - - File tempLibs = new File(tempDir.toFile(), "libs"); - tempLibs.mkdirs(); - tempLibs.deleteOnExit(); - - mockContext = mock(BundleContext.class); - - framework = mock(Framework.class); - TestFrameworkFactory.setFramework(framework); - when(framework.getBundleContext()).thenReturn(mockContext); - - Bundle mockBundle = mock(Bundle.class); - when(mockContext.installBundle(any(String.class))).thenReturn(mockBundle); - when(mockBundle.getHeaders()).thenReturn(new Hashtable<String, String>()); - ServiceTracker registryTracker = mock(ServiceTracker.class); - PowerMockito - .whenNew(ServiceTracker.class) - .withParameterTypes(BundleContext.class, String.class, - ServiceTrackerCustomizer.class) - .withArguments(any(BundleContext.class), - eq(BundleManager.class.getName()), any(ServiceTrackerCustomizer.class)) - .thenReturn(registryTracker); - bundleManager = new FakeBundleManager(); - when(registryTracker.waitForService(0)).thenReturn(bundleManager); - ServiceTracker launcherTracker = mock(ServiceTracker.class); - launcher = mock(Launcher.class); - PowerMockito - .whenNew(ServiceTracker.class) - .withParameterTypes(BundleContext.class, String.class, - ServiceTrackerCustomizer.class) - .withArguments(any(BundleContext.class), - eq(Launcher.class.getName()), - any(ServiceTrackerCustomizer.class)) - .thenReturn(launcherTracker); - when(launcherTracker.waitForService(0)) - .thenReturn(launcher); - - Path osgiDir; - - osgiDir = tempDir.resolve("osgi-cache"); - osgiDir.toFile().mkdirs(); - osgiDir.toFile().deleteOnExit(); - assertTrue(osgiDir.toFile().exists()); - } - - @After - public void clearSystemProperties() { - if (savedHome == null) { - System.clearProperty(THERMOSTAT_HOME_PROPERTY); - } else { - System.setProperty(THERMOSTAT_HOME_PROPERTY, savedHome); - savedHome = null; - } - if (savedUserHome == null) { - System.clearProperty(USER_THERMOSTAT_HOME_PROPERTY); - } else { - System.setProperty(USER_THERMOSTAT_HOME_PROPERTY, savedUserHome); - savedUserHome = null; - } - paths = null; - } - - @Test - public void testStartRunsOSGiFramework() throws Exception { - FrameworkOptionsProcessor opts = new FrameworkOptionsProcessor(new String[] {}); - FrameworkProvider provider = new FrameworkProvider(paths, opts); - - provider.start(new String[] {}); - - verify(framework).init(); - verify(framework).start(); - } - - @Test - public void testStartRunsLauncher() throws Exception { - FrameworkOptionsProcessor opts = new FrameworkOptionsProcessor(new String[] {}); - FrameworkProvider provider = new FrameworkProvider(paths, opts); - - provider.start(new String[] {}); - - verify(launcher).run(new String[] {}, false); - } - - @Test - public void testPrintOSGiInfoParameterIsPassedToBundleManager() { - FrameworkOptionsProcessor opts = mock(FrameworkOptionsProcessor.class); - when(opts.printOsgiInfo()).thenReturn(true); - FrameworkProvider provider = new FrameworkProvider(paths, opts); - - provider.start(new String[] {}); - - assertEquals(true, bundleManager.printOSGiInfo); - } - - @Test - public void testIgnoreBundleVersionsParameterIsPassedToBundleManager() { - FrameworkOptionsProcessor opts = mock(FrameworkOptionsProcessor.class); - when(opts.ignoreBundleVersions()).thenReturn(true); - FrameworkProvider provider = new FrameworkProvider(paths, opts); - - provider.start(new String[] {}); - - assertEquals(true, bundleManager.ignoreBundleVersion); - } - - @Test - public void testNullBootDelegationIsNotSetInConfiguration() { - FrameworkOptionsProcessor opts = mock(FrameworkOptionsProcessor.class); - when(opts.bootDelegationValue()).thenReturn(null); - FrameworkProvider provider = new FrameworkProvider(paths, opts); - - provider.start(new String[] {}); - - Map<String, String> config = TestFrameworkFactory.getConfig(); - assertFalse(config.containsKey(Constants.FRAMEWORK_BOOTDELEGATION)); - } - - @Test - public void testPackagesListedInBootDelegationArePassedToFramework() { - FrameworkOptionsProcessor opts = mock(FrameworkOptionsProcessor.class); - when(opts.bootDelegationValue()).thenReturn("foo"); - FrameworkProvider provider = new FrameworkProvider(paths, opts); - - provider.start(new String[] {}); - - Map<String, String> config = TestFrameworkFactory.getConfig(); - assertEquals("foo", config.get(Constants.FRAMEWORK_BOOTDELEGATION)); - } - -}
--- a/main/src/test/java/com/redhat/thermostat/main/impl/TestFrameworkFactory.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Copyright 2012-2016 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.main.impl; - -import java.util.Map; - -import org.osgi.framework.launch.Framework; -import org.osgi.framework.launch.FrameworkFactory; - -/** Registered using ServiceLoader */ -public class TestFrameworkFactory implements FrameworkFactory { - - private static Framework framework; - private static Map<String, String> config; - - public static void setFramework(Framework framework) { - TestFrameworkFactory.framework = framework; - } - - public static Map<String,String> getConfig() { - return config; - } - - // NOTE: For some unknown reason, this doesn't compile when declared - // as newFramework(Map<String,String> config). At least not in Maven. - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Override - public Framework newFramework(Map config) { - TestFrameworkFactory.config = config; - return framework; - } - -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/src/test/java/com/redhat/thermostat/main/internal/FrameworkOptionsProcessorTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright 2012-2016 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.main.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; + +import org.junit.Test; + +import com.redhat.thermostat.main.internal.FrameworkOptionsProcessor; + +public class FrameworkOptionsProcessorTest { + + @Test + public void verifyDefaults() { + String[] args = new String[] { "help" }; + FrameworkOptionsProcessor opts = new FrameworkOptionsProcessor(args); + assertFalse(opts.printOsgiInfo()); + assertFalse(opts.ignoreBundleVersions()); + assertTrue(opts.bootDelegationValue().contains("com.redhat.thermostat.vm.profiler")); + assertEquals(Arrays.asList("help"), Arrays.asList(opts.getOtherOptions())); + } + + @Test + public void canGetPrintOsgiInfo() { + String[] args = new String[] { "--print-osgi-info", "help" }; + FrameworkOptionsProcessor opts = new FrameworkOptionsProcessor(args); + assertTrue(opts.printOsgiInfo()); + assertEquals(Arrays.asList("help"), + Arrays.asList(opts.getOtherOptions())); + } + + @Test + public void canGetBootDelegation() { + String[] args = new String[] { "--boot-delegation=foo", "help" }; + FrameworkOptionsProcessor opts = new FrameworkOptionsProcessor(args); + assertEquals("foo", opts.bootDelegationValue()); + assertEquals(Arrays.asList("help"), + Arrays.asList(opts.getOtherOptions())); + } + + @Test + public void canGetIgnoreBundleVersion() { + String[] args = new String[] { "--ignore-bundle-versions", "help" }; + FrameworkOptionsProcessor opts = new FrameworkOptionsProcessor(args); + assertTrue(opts.ignoreBundleVersions()); + assertEquals(Arrays.asList("help"), + Arrays.asList(opts.getOtherOptions())); + } + + @Test(expected = RuntimeException.class) + public void emtpyStringForBootDelegationThrowsException() { + String[] args = new String[] { "--boot-delegation=", "help" }; + // This is expected to fail since the boot delegation value is an empty + // string. + new FrameworkOptionsProcessor(args); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/src/test/java/com/redhat/thermostat/main/internal/FrameworkProviderTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,274 @@ +/* + * Copyright 2012-2016 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.main.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.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collections; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.osgi.framework.Constants; +import org.osgi.framework.launch.Framework; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.redhat.thermostat.launcher.BundleInformation; +import com.redhat.thermostat.launcher.BundleManager; +import com.redhat.thermostat.launcher.Launcher; +import com.redhat.thermostat.main.internal.FrameworkOptionsProcessor; +import com.redhat.thermostat.main.internal.FrameworkProvider; +import com.redhat.thermostat.shared.config.CommonPaths; +import com.redhat.thermostat.shared.config.internal.CommonPathsImpl; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({FrameworkProvider.class}) +public class FrameworkProviderTest { + + private static final String THERMOSTAT_HOME_PROPERTY = "THERMOSTAT_HOME"; + private static final String USER_THERMOSTAT_HOME_PROPERTY = "USER_THERMOSTAT_HOME"; + + private BundleContext mockContext; + + private Framework framework; + + private FakeBundleManager bundleManager; + private Launcher launcher; + private CommonPaths paths; + private String savedHome, savedUserHome; + + static class FakeBundleManager extends BundleManager /* extends BundleManagerImpl */ { + + private boolean printOSGiInfo; + private boolean ignoreBundleVersion; + + @Override + public void loadBundlesByName(List<BundleInformation> bundles) throws BundleException, IOException { + // do nothing + } + + @Override + public CommonPaths getCommonPaths() { + return null; + } + + // @Override + public void setPrintOSGiInfo(boolean print) { + this.printOSGiInfo = print; + } + + // @Override + public void setIgnoreBundleVersions(boolean ignore) { + this.ignoreBundleVersion = ignore; + } + + } + + @SuppressWarnings("rawtypes") + @Before + public void setUp() throws Exception { + Path tempDir; + tempDir = Files.createTempDirectory("FrameworkProviderTest"); + tempDir.toFile().deleteOnExit(); + savedHome = System.setProperty(THERMOSTAT_HOME_PROPERTY, tempDir.toString()); + savedUserHome = System.setProperty(USER_THERMOSTAT_HOME_PROPERTY, tempDir.toString()); + paths = new CommonPathsImpl(); + + File tempEtc = new File(tempDir.toFile(), "etc"); + tempEtc.mkdirs(); + tempEtc.deleteOnExit(); + + File tempProps = new File(tempEtc, "osgi-export.properties"); + tempProps.createNewFile(); + tempProps.deleteOnExit(); + + File tempBundleProps = new File(tempEtc, "bundles.properties"); + tempBundleProps.createNewFile(); + tempBundleProps.deleteOnExit(); + + File tempLibs = new File(tempDir.toFile(), "libs"); + tempLibs.mkdirs(); + tempLibs.deleteOnExit(); + + mockContext = mock(BundleContext.class); + + framework = mock(Framework.class); + TestFrameworkFactory.setFramework(framework); + when(framework.getBundleContext()).thenReturn(mockContext); + + Bundle mockBundle = mock(Bundle.class); + when(mockContext.installBundle(any(String.class))).thenReturn(mockBundle); + when(mockBundle.getHeaders()).thenReturn(new Hashtable<String, String>()); + ServiceTracker registryTracker = mock(ServiceTracker.class); + PowerMockito + .whenNew(ServiceTracker.class) + .withParameterTypes(BundleContext.class, String.class, + ServiceTrackerCustomizer.class) + .withArguments(any(BundleContext.class), + eq(BundleManager.class.getName()), any(ServiceTrackerCustomizer.class)) + .thenReturn(registryTracker); + bundleManager = new FakeBundleManager(); + when(registryTracker.waitForService(0)).thenReturn(bundleManager); + ServiceTracker launcherTracker = mock(ServiceTracker.class); + launcher = mock(Launcher.class); + PowerMockito + .whenNew(ServiceTracker.class) + .withParameterTypes(BundleContext.class, String.class, + ServiceTrackerCustomizer.class) + .withArguments(any(BundleContext.class), + eq(Launcher.class.getName()), + any(ServiceTrackerCustomizer.class)) + .thenReturn(launcherTracker); + when(launcherTracker.waitForService(0)) + .thenReturn(launcher); + + Path osgiDir; + + osgiDir = tempDir.resolve("osgi-cache"); + osgiDir.toFile().mkdirs(); + osgiDir.toFile().deleteOnExit(); + assertTrue(osgiDir.toFile().exists()); + } + + @After + public void clearSystemProperties() { + if (savedHome == null) { + System.clearProperty(THERMOSTAT_HOME_PROPERTY); + } else { + System.setProperty(THERMOSTAT_HOME_PROPERTY, savedHome); + savedHome = null; + } + if (savedUserHome == null) { + System.clearProperty(USER_THERMOSTAT_HOME_PROPERTY); + } else { + System.setProperty(USER_THERMOSTAT_HOME_PROPERTY, savedUserHome); + savedUserHome = null; + } + paths = null; + } + + @Test + public void testStartRunsOSGiFramework() throws Exception { + FrameworkOptionsProcessor opts = new FrameworkOptionsProcessor(new String[] {}); + FrameworkProvider provider = new FrameworkProvider(paths, opts); + + provider.start(new String[] {}); + + verify(framework).init(); + verify(framework).start(); + } + + @Test + public void testStartRunsLauncher() throws Exception { + FrameworkOptionsProcessor opts = new FrameworkOptionsProcessor(new String[] {}); + FrameworkProvider provider = new FrameworkProvider(paths, opts); + + provider.start(new String[] {}); + + verify(launcher).run(new String[] {}, false); + } + + @Test + public void testPrintOSGiInfoParameterIsPassedToBundleManager() { + FrameworkOptionsProcessor opts = mock(FrameworkOptionsProcessor.class); + when(opts.printOsgiInfo()).thenReturn(true); + FrameworkProvider provider = new FrameworkProvider(paths, opts); + + provider.start(new String[] {}); + + assertEquals(true, bundleManager.printOSGiInfo); + } + + @Test + public void testIgnoreBundleVersionsParameterIsPassedToBundleManager() { + FrameworkOptionsProcessor opts = mock(FrameworkOptionsProcessor.class); + when(opts.ignoreBundleVersions()).thenReturn(true); + FrameworkProvider provider = new FrameworkProvider(paths, opts); + + provider.start(new String[] {}); + + assertEquals(true, bundleManager.ignoreBundleVersion); + } + + @Test + public void testNullBootDelegationIsNotSetInConfiguration() { + FrameworkOptionsProcessor opts = mock(FrameworkOptionsProcessor.class); + when(opts.bootDelegationValue()).thenReturn(null); + FrameworkProvider provider = new FrameworkProvider(paths, opts); + + provider.start(new String[] {}); + + Map<String, String> config = TestFrameworkFactory.getConfig(); + assertFalse(config.containsKey(Constants.FRAMEWORK_BOOTDELEGATION)); + } + + @Test + public void testPackagesListedInBootDelegationArePassedToFramework() { + FrameworkOptionsProcessor opts = mock(FrameworkOptionsProcessor.class); + when(opts.bootDelegationValue()).thenReturn("foo"); + FrameworkProvider provider = new FrameworkProvider(paths, opts); + + provider.start(new String[] {}); + + Map<String, String> config = TestFrameworkFactory.getConfig(); + assertEquals("foo", config.get(Constants.FRAMEWORK_BOOTDELEGATION)); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/src/test/java/com/redhat/thermostat/main/internal/TestFrameworkFactory.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,68 @@ +/* + * Copyright 2012-2016 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.main.internal; + +import java.util.Map; + +import org.osgi.framework.launch.Framework; +import org.osgi.framework.launch.FrameworkFactory; + +/** Registered using ServiceLoader */ +public class TestFrameworkFactory implements FrameworkFactory { + + private static Framework framework; + private static Map<String, String> config; + + public static void setFramework(Framework framework) { + TestFrameworkFactory.framework = framework; + } + + public static Map<String,String> getConfig() { + return config; + } + + // NOTE: For some unknown reason, this doesn't compile when declared + // as newFramework(Map<String,String> config). At least not in Maven. + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public Framework newFramework(Map config) { + TestFrameworkFactory.config = config; + return framework; + } + +} +
--- a/main/src/test/resources/META-INF/services/org.osgi.framework.launch.FrameworkFactory Wed Apr 06 14:52:26 2016 +0200 +++ b/main/src/test/resources/META-INF/services/org.osgi.framework.launch.FrameworkFactory Fri Apr 08 13:18:48 2016 +0200 @@ -1,5 +1,5 @@ # -# Copyright 2012-2014 Red Hat, Inc. +# Copyright 2012-2016 Red Hat, Inc. # # This file is part of Thermostat. # @@ -34,5 +34,5 @@ # to do so, delete this exception statement from your version. # -com.redhat.thermostat.main.impl.TestFrameworkFactory +com.redhat.thermostat.main.internal.TestFrameworkFactory
--- a/thread/client-common/pom.xml Wed Apr 06 14:52:26 2016 +0200 +++ b/thread/client-common/pom.xml Fri Apr 08 13:18:48 2016 +0200 @@ -124,7 +124,7 @@ com.redhat.thermostat.thread.client.common.collector, </Export-Package> <Private-Package> - com.redhat.thermostat.thread.client.common.collector.impl, + com.redhat.thermostat.thread.client.common.collector.internal, com.redhat.thermostat.thread.client.common.osgi, </Private-Package> <!-- Do not autogenerate uses clauses in Manifests -->
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/impl/ThreadCollectorFactoryImpl.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.common.collector.impl; - -import org.osgi.framework.BundleContext; -import org.osgi.framework.FrameworkUtil; - -import com.redhat.thermostat.storage.core.VmRef; -import com.redhat.thermostat.storage.dao.AgentInfoDAO; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory; -import com.redhat.thermostat.thread.dao.ThreadDao; - -public class ThreadCollectorFactoryImpl implements ThreadCollectorFactory { - - private BundleContext context; - private AgentInfoDAO agentDao; - private ThreadDao threadDao; - - public ThreadCollectorFactoryImpl() { - this(FrameworkUtil.getBundle(ThreadCollectorFactoryImpl.class).getBundleContext()); - } - - ThreadCollectorFactoryImpl(BundleContext context) { - this.context = context; - } - - public void setAgentDao(AgentInfoDAO agentDao) { - this.agentDao = agentDao; - } - - public void setThreadDao(ThreadDao threadDao) { - this.threadDao = threadDao; - } - - @Override - public synchronized ThreadCollector getCollector(VmRef reference) { - // TODO set the values when the agent/thread dao changes - ThreadMXBeanCollector result = new ThreadMXBeanCollector(context, reference); - result.setAgentInfoDao(agentDao); - result.setThreadDao(threadDao); - return result; - } -} -
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/impl/ThreadMXBeanCollector.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,278 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.common.collector.impl; - -import java.net.InetSocketAddress; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; - -import com.redhat.thermostat.client.command.RequestQueue; -import com.redhat.thermostat.common.command.Request; -import com.redhat.thermostat.common.command.Request.RequestType; -import com.redhat.thermostat.common.command.RequestResponseListener; -import com.redhat.thermostat.common.command.Response; -import com.redhat.thermostat.common.model.Range; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.storage.core.AgentId; -import com.redhat.thermostat.storage.core.VmRef; -import com.redhat.thermostat.storage.core.experimental.statement.ResultHandler; -import com.redhat.thermostat.storage.dao.AgentInfoDAO; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; -import com.redhat.thermostat.thread.collector.HarvesterCommand; -import com.redhat.thermostat.thread.dao.ThreadDao; -import com.redhat.thermostat.thread.model.SessionID; -import com.redhat.thermostat.thread.model.ThreadHarvestingStatus; -import com.redhat.thermostat.thread.model.ThreadSession; -import com.redhat.thermostat.thread.model.ThreadState; -import com.redhat.thermostat.thread.model.ThreadSummary; -import com.redhat.thermostat.thread.model.VmDeadLockData; - -public class ThreadMXBeanCollector implements ThreadCollector { - - private static final Range<Long> FULL_RANGE = new Range<>(0l, Long.MAX_VALUE); - private static final int ALL = -1; - private static final int FIRST = 1; - - private static final String CMD_CHANNEL_ACTION_NAME = "thread-harvester"; - private static final Logger logger = LoggingUtils.getLogger(ThreadMXBeanCollector.class); - - private AgentInfoDAO agentDao; - private ThreadDao threadDao; - private BundleContext context; - private VmRef ref; - - public ThreadMXBeanCollector(BundleContext context, VmRef ref) { - this.context = context; - this.ref = ref; - } - - @Override - public void setThreadDao(ThreadDao threadDao) { - this.threadDao = threadDao; - } - - @Override - public void setAgentInfoDao(AgentInfoDAO agentDao) { - this.agentDao = agentDao; - } - - Request createRequest() { - AgentId targetId = new AgentId(ref.getHostRef().getAgentId()); - - InetSocketAddress target = agentDao.getAgentInformation(targetId).getRequestQueueAddress(); - Request harvester = new Request(RequestType.RESPONSE_EXPECTED, target); - - harvester.setReceiver(HarvesterCommand.RECEIVER); - - return harvester; - } - - @Override - public boolean startHarvester() { - - Request harvester = createRequest(); - harvester.setParameter(Request.ACTION, CMD_CHANNEL_ACTION_NAME); - harvester.setParameter(HarvesterCommand.class.getName(), HarvesterCommand.START.name()); - harvester.setParameter(HarvesterCommand.VM_ID.name(), ref.getVmId()); - harvester.setParameter(HarvesterCommand.VM_PID.name(), String.valueOf(ref.getPid())); - - return postAndWait(harvester); - - } - - @Override - public boolean stopHarvester() { - - Request harvester = createRequest(); - harvester.setParameter(Request.ACTION, CMD_CHANNEL_ACTION_NAME); - harvester.setParameter(HarvesterCommand.class.getName(), HarvesterCommand.STOP.name()); - harvester.setParameter(HarvesterCommand.VM_ID.name(), ref.getVmId()); - - boolean result = postAndWait(harvester); - return result; - } - - @Override - public boolean isHarvesterCollecting() { - ThreadHarvestingStatus status = threadDao.getLatestHarvestingStatus(ref); - if (status == null) { - return false; - } - return status.isHarvesting(); - } - - @Override - public List<ThreadSession> getThreadSessions(Range<Long> range) { - return threadDao.getSessions(ref, range, ALL, ThreadDao.Sort.ASCENDING); - } - - @Override - public SessionID getLastThreadSession() { - List<ThreadSession> sessions = - threadDao.getSessions(ref, FULL_RANGE, FIRST, - ThreadDao.Sort.DESCENDING); - return sessions.isEmpty() ? null : new SessionID(sessions.get(0).getSession()); - } - - @Override - public ThreadSummary getLatestThreadSummary() { - List<ThreadSummary> summaries = threadDao.getSummary(ref, FULL_RANGE, FIRST); - ThreadSummary summary = null; - if (summaries.isEmpty()) { - // default to all 0 - summary = new ThreadSummary(); - } else { - summary = summaries.get(0); - } - - return summary; - } - - @Override - public Range<Long> getThreadRange(SessionID session) { - - final long[] timestamps = new long[2]; - timestamps[0] = 0l; - timestamps[1] = Long.MAX_VALUE; - - threadDao.getThreadStates(ref, session, - new ResultHandler<ThreadState>() { - @Override - public boolean onResult(ThreadState result) { - timestamps[1] = result.getTimeStamp(); - return false; - } - }, - FULL_RANGE, FIRST, ThreadDao.Sort.DESCENDING); - - threadDao.getThreadStates(ref, session, - new ResultHandler<ThreadState>() { - @Override - public boolean onResult(ThreadState result) { - timestamps[0] = result.getTimeStamp(); - return false; - } - }, - FULL_RANGE, FIRST, ThreadDao.Sort.ASCENDING); - - return new Range<>(timestamps[0], timestamps[1]); - } - - @Override - public void getThreadStates(SessionID session, - ResultHandler<ThreadState> handler, - Range<Long> range) - { - threadDao.getThreadStates(ref, session, handler, range, - ALL, - ThreadDao.Sort.ASCENDING); - } - - @Override - public List<ThreadSummary> getThreadSummary(Range<Long> range) { - List<ThreadSummary> summary = threadDao.getSummary(ref, range, Integer.MAX_VALUE); - return summary; - } - - @Override - public VmDeadLockData getLatestDeadLockData() { - return threadDao.loadLatestDeadLockStatus(ref); - } - - @Override - public void requestDeadLockCheck() { - Request harvester = createRequest(); - harvester.setParameter(Request.ACTION, CMD_CHANNEL_ACTION_NAME); - harvester.setParameter(HarvesterCommand.class.getName(), HarvesterCommand.FIND_DEADLOCKS.name()); - harvester.setParameter(HarvesterCommand.VM_ID.name(), ref.getVmId()); - harvester.setParameter(HarvesterCommand.VM_PID.name(), String.valueOf(ref.getPid())); - - postAndWait(harvester); - } - - private boolean postAndWait(Request harvester) { - final CountDownLatch latch = new CountDownLatch(1); - final boolean[] result = new boolean[1]; - - harvester.addListener(new RequestResponseListener() { - @Override - public void fireComplete(Request request, Response response) { - switch (response.getType()) { - case OK: - result[0] = true; - break; - default: - break; - } - latch.countDown(); - } - }); - - try { - enqueueRequest(harvester); - latch.await(); - } catch (CommandChannelException e) { - logger.log(Level.WARNING, "Failed to enqueue request", e); - } catch (InterruptedException ignore) {} - return result[0]; - } - - private void enqueueRequest(Request req) throws CommandChannelException { - ServiceReference ref = context.getServiceReference(RequestQueue.class.getName()); - if (ref == null) { - throw new CommandChannelException("Cannot access command channel"); - } - RequestQueue queue = (RequestQueue) context.getService(ref); - queue.putRequest(req); - context.ungetService(ref); - } - - @SuppressWarnings("serial") - private class CommandChannelException extends Exception { - - public CommandChannelException(String message) { - super(message); - } - - } -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/internal/ThreadCollectorFactoryImpl.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright 2012-2016 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.thread.client.common.collector.internal; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; + +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory; +import com.redhat.thermostat.thread.dao.ThreadDao; + +public class ThreadCollectorFactoryImpl implements ThreadCollectorFactory { + + private BundleContext context; + private AgentInfoDAO agentDao; + private ThreadDao threadDao; + + public ThreadCollectorFactoryImpl() { + this(FrameworkUtil.getBundle(ThreadCollectorFactoryImpl.class).getBundleContext()); + } + + ThreadCollectorFactoryImpl(BundleContext context) { + this.context = context; + } + + public void setAgentDao(AgentInfoDAO agentDao) { + this.agentDao = agentDao; + } + + public void setThreadDao(ThreadDao threadDao) { + this.threadDao = threadDao; + } + + @Override + public synchronized ThreadCollector getCollector(VmRef reference) { + // TODO set the values when the agent/thread dao changes + ThreadMXBeanCollector result = new ThreadMXBeanCollector(context, reference); + result.setAgentInfoDao(agentDao); + result.setThreadDao(threadDao); + return result; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/internal/ThreadMXBeanCollector.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,278 @@ +/* + * Copyright 2012-2016 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.thread.client.common.collector.internal; + +import java.net.InetSocketAddress; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; + +import com.redhat.thermostat.client.command.RequestQueue; +import com.redhat.thermostat.common.command.Request; +import com.redhat.thermostat.common.command.Request.RequestType; +import com.redhat.thermostat.common.command.RequestResponseListener; +import com.redhat.thermostat.common.command.Response; +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.storage.core.AgentId; +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.core.experimental.statement.ResultHandler; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.collector.HarvesterCommand; +import com.redhat.thermostat.thread.dao.ThreadDao; +import com.redhat.thermostat.thread.model.SessionID; +import com.redhat.thermostat.thread.model.ThreadHarvestingStatus; +import com.redhat.thermostat.thread.model.ThreadSession; +import com.redhat.thermostat.thread.model.ThreadState; +import com.redhat.thermostat.thread.model.ThreadSummary; +import com.redhat.thermostat.thread.model.VmDeadLockData; + +public class ThreadMXBeanCollector implements ThreadCollector { + + private static final Range<Long> FULL_RANGE = new Range<>(0l, Long.MAX_VALUE); + private static final int ALL = -1; + private static final int FIRST = 1; + + private static final String CMD_CHANNEL_ACTION_NAME = "thread-harvester"; + private static final Logger logger = LoggingUtils.getLogger(ThreadMXBeanCollector.class); + + private AgentInfoDAO agentDao; + private ThreadDao threadDao; + private BundleContext context; + private VmRef ref; + + public ThreadMXBeanCollector(BundleContext context, VmRef ref) { + this.context = context; + this.ref = ref; + } + + @Override + public void setThreadDao(ThreadDao threadDao) { + this.threadDao = threadDao; + } + + @Override + public void setAgentInfoDao(AgentInfoDAO agentDao) { + this.agentDao = agentDao; + } + + Request createRequest() { + AgentId targetId = new AgentId(ref.getHostRef().getAgentId()); + + InetSocketAddress target = agentDao.getAgentInformation(targetId).getRequestQueueAddress(); + Request harvester = new Request(RequestType.RESPONSE_EXPECTED, target); + + harvester.setReceiver(HarvesterCommand.RECEIVER); + + return harvester; + } + + @Override + public boolean startHarvester() { + + Request harvester = createRequest(); + harvester.setParameter(Request.ACTION, CMD_CHANNEL_ACTION_NAME); + harvester.setParameter(HarvesterCommand.class.getName(), HarvesterCommand.START.name()); + harvester.setParameter(HarvesterCommand.VM_ID.name(), ref.getVmId()); + harvester.setParameter(HarvesterCommand.VM_PID.name(), String.valueOf(ref.getPid())); + + return postAndWait(harvester); + + } + + @Override + public boolean stopHarvester() { + + Request harvester = createRequest(); + harvester.setParameter(Request.ACTION, CMD_CHANNEL_ACTION_NAME); + harvester.setParameter(HarvesterCommand.class.getName(), HarvesterCommand.STOP.name()); + harvester.setParameter(HarvesterCommand.VM_ID.name(), ref.getVmId()); + + boolean result = postAndWait(harvester); + return result; + } + + @Override + public boolean isHarvesterCollecting() { + ThreadHarvestingStatus status = threadDao.getLatestHarvestingStatus(ref); + if (status == null) { + return false; + } + return status.isHarvesting(); + } + + @Override + public List<ThreadSession> getThreadSessions(Range<Long> range) { + return threadDao.getSessions(ref, range, ALL, ThreadDao.Sort.ASCENDING); + } + + @Override + public SessionID getLastThreadSession() { + List<ThreadSession> sessions = + threadDao.getSessions(ref, FULL_RANGE, FIRST, + ThreadDao.Sort.DESCENDING); + return sessions.isEmpty() ? null : new SessionID(sessions.get(0).getSession()); + } + + @Override + public ThreadSummary getLatestThreadSummary() { + List<ThreadSummary> summaries = threadDao.getSummary(ref, FULL_RANGE, FIRST); + ThreadSummary summary = null; + if (summaries.isEmpty()) { + // default to all 0 + summary = new ThreadSummary(); + } else { + summary = summaries.get(0); + } + + return summary; + } + + @Override + public Range<Long> getThreadRange(SessionID session) { + + final long[] timestamps = new long[2]; + timestamps[0] = 0l; + timestamps[1] = Long.MAX_VALUE; + + threadDao.getThreadStates(ref, session, + new ResultHandler<ThreadState>() { + @Override + public boolean onResult(ThreadState result) { + timestamps[1] = result.getTimeStamp(); + return false; + } + }, + FULL_RANGE, FIRST, ThreadDao.Sort.DESCENDING); + + threadDao.getThreadStates(ref, session, + new ResultHandler<ThreadState>() { + @Override + public boolean onResult(ThreadState result) { + timestamps[0] = result.getTimeStamp(); + return false; + } + }, + FULL_RANGE, FIRST, ThreadDao.Sort.ASCENDING); + + return new Range<>(timestamps[0], timestamps[1]); + } + + @Override + public void getThreadStates(SessionID session, + ResultHandler<ThreadState> handler, + Range<Long> range) + { + threadDao.getThreadStates(ref, session, handler, range, + ALL, + ThreadDao.Sort.ASCENDING); + } + + @Override + public List<ThreadSummary> getThreadSummary(Range<Long> range) { + List<ThreadSummary> summary = threadDao.getSummary(ref, range, Integer.MAX_VALUE); + return summary; + } + + @Override + public VmDeadLockData getLatestDeadLockData() { + return threadDao.loadLatestDeadLockStatus(ref); + } + + @Override + public void requestDeadLockCheck() { + Request harvester = createRequest(); + harvester.setParameter(Request.ACTION, CMD_CHANNEL_ACTION_NAME); + harvester.setParameter(HarvesterCommand.class.getName(), HarvesterCommand.FIND_DEADLOCKS.name()); + harvester.setParameter(HarvesterCommand.VM_ID.name(), ref.getVmId()); + harvester.setParameter(HarvesterCommand.VM_PID.name(), String.valueOf(ref.getPid())); + + postAndWait(harvester); + } + + private boolean postAndWait(Request harvester) { + final CountDownLatch latch = new CountDownLatch(1); + final boolean[] result = new boolean[1]; + + harvester.addListener(new RequestResponseListener() { + @Override + public void fireComplete(Request request, Response response) { + switch (response.getType()) { + case OK: + result[0] = true; + break; + default: + break; + } + latch.countDown(); + } + }); + + try { + enqueueRequest(harvester); + latch.await(); + } catch (CommandChannelException e) { + logger.log(Level.WARNING, "Failed to enqueue request", e); + } catch (InterruptedException ignore) {} + return result[0]; + } + + private void enqueueRequest(Request req) throws CommandChannelException { + ServiceReference ref = context.getServiceReference(RequestQueue.class.getName()); + if (ref == null) { + throw new CommandChannelException("Cannot access command channel"); + } + RequestQueue queue = (RequestQueue) context.getService(ref); + queue.putRequest(req); + context.ungetService(ref); + } + + @SuppressWarnings("serial") + private class CommandChannelException extends Exception { + + public CommandChannelException(String message) { + super(message); + } + + } +} +
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/osgi/Activator.java Wed Apr 06 14:52:26 2016 +0200 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/osgi/Activator.java Fri Apr 08 13:18:48 2016 +0200 @@ -43,7 +43,7 @@ import com.redhat.thermostat.storage.dao.AgentInfoDAO; import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory; -import com.redhat.thermostat.thread.client.common.collector.impl.ThreadCollectorFactoryImpl; +import com.redhat.thermostat.thread.client.common.collector.internal.ThreadCollectorFactoryImpl; import com.redhat.thermostat.thread.dao.ThreadDao; public class Activator implements BundleActivator {
--- a/thread/client-common/src/test/java/com/redhat/thermostat/thread/client/common/collector/impl/ThreadCollectorFactoryImplTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.common.collector.impl; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.mock; - -import org.junit.Test; - -import com.redhat.thermostat.storage.core.VmRef; -import com.redhat.thermostat.storage.dao.AgentInfoDAO; -import com.redhat.thermostat.testutils.StubBundleContext; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory; -import com.redhat.thermostat.thread.client.common.collector.impl.ThreadCollectorFactoryImpl; -import com.redhat.thermostat.thread.dao.ThreadDao; - -public class ThreadCollectorFactoryImplTest { - - @Test - public void testThreadCollectorFactory() { - StubBundleContext context = new StubBundleContext(); - VmRef reference = mock(VmRef.class); - - ThreadCollectorFactory factory = new ThreadCollectorFactoryImpl(context); - ThreadCollector collector = factory.getCollector(reference); - assertNotNull(collector); - } - - @Test - public void testThreadCollectorFactoryWithAgentAndThreadDaos() { - StubBundleContext context = new StubBundleContext(); - AgentInfoDAO agentDao = mock(AgentInfoDAO.class); - ThreadDao threadDao = mock(ThreadDao.class); - VmRef reference = mock(VmRef.class); - - ThreadCollectorFactory factory = new ThreadCollectorFactoryImpl(context); - factory.setAgentDao(agentDao); - factory.setThreadDao(threadDao); - ThreadCollector collector = factory.getCollector(reference); - assertNotNull(collector); - } -} -
--- a/thread/client-common/src/test/java/com/redhat/thermostat/thread/client/common/collector/impl/ThreadCollectorTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,223 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.common.collector.impl; - -import com.redhat.thermostat.client.command.RequestQueue; -import com.redhat.thermostat.common.command.Request; -import com.redhat.thermostat.common.command.RequestResponseListener; -import com.redhat.thermostat.common.command.Response; -import com.redhat.thermostat.common.command.Response.ResponseType; -import com.redhat.thermostat.storage.core.VmRef; -import com.redhat.thermostat.storage.dao.AgentInfoDAO; -import com.redhat.thermostat.testutils.StubBundleContext; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; -import com.redhat.thermostat.thread.collector.HarvesterCommand; -import com.redhat.thermostat.thread.dao.ThreadDao; -import com.redhat.thermostat.thread.model.ThreadHarvestingStatus; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class ThreadCollectorTest { - - private StubBundleContext context; - private ThreadDao threadDao; - private VmRef reference; - private Request request; - private AgentInfoDAO agentDao; - - @Before - public void setup() { - context = new StubBundleContext(); - request = mock(Request.class); - agentDao = mock(AgentInfoDAO.class); - threadDao = mock(ThreadDao.class); - reference = mock(VmRef.class); - when(reference.getVmId()).thenReturn("00101010"); - - final Response response = mock(Response.class); - when(response.getType()).thenReturn(ResponseType.OK); - - final ArgumentCaptor<RequestResponseListener> captor = ArgumentCaptor.forClass(RequestResponseListener.class); - doNothing().when(request).addListener(captor.capture()); - } - - @Test - public void testHarvesterCollecting() { - ThreadHarvestingStatus status = mock(ThreadHarvestingStatus.class); - when(status.isHarvesting()).thenReturn(true); - ThreadCollector collector = new ThreadMXBeanCollector(context, reference); - when(threadDao.getLatestHarvestingStatus(reference)).thenReturn(status); - - collector.setThreadDao(threadDao); - - assertTrue(collector.isHarvesterCollecting()); - } - - @Test - public void testStart() { - final RequestQueue requestQueue = mock(RequestQueue.class); - context.registerService(RequestQueue.class, requestQueue, null); - - final Response response = mock(Response.class); - when(response.getType()).thenReturn(ResponseType.OK); - - final ArgumentCaptor<RequestResponseListener> captor = ArgumentCaptor.forClass(RequestResponseListener.class); - doNothing().when(request).addListener(captor.capture()); - - doAnswer(new Answer<Void>() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - Request req = (Request) invocation.getArguments()[0]; - assertSame(request, req); - - RequestResponseListener listener = captor.getValue(); - listener.fireComplete(request, response); - - return null; - } - - }).when(requestQueue).putRequest(request); - - ThreadCollector collector = new ThreadMXBeanCollector(context, reference) { - @Override - Request createRequest() { - return request; - } - }; - collector.setAgentInfoDao(agentDao); - collector.setThreadDao(threadDao); - - collector.startHarvester(); - - verify(request).setParameter(HarvesterCommand.class.getName(), HarvesterCommand.START.name()); - verify(request).setParameter(HarvesterCommand.VM_ID.name(), "00101010"); - - verify(requestQueue).putRequest(request); - } - - @Test - public void testStartNoRequestQueue() { - ThreadCollector collector = new ThreadMXBeanCollector(context, reference) { - @Override - Request createRequest() { - return request; - } - }; - collector.setAgentInfoDao(agentDao); - collector.setThreadDao(threadDao); - - boolean result = collector.startHarvester(); - - verify(request).setParameter(HarvesterCommand.class.getName(), HarvesterCommand.START.name()); - verify(request).setParameter(HarvesterCommand.VM_ID.name(), "00101010"); - - assertFalse(result); - } - - @Test - public void testStop() { - final RequestQueue requestQueue = mock(RequestQueue.class); - context.registerService(RequestQueue.class, requestQueue, null); - - final Response response = mock(Response.class); - when(response.getType()).thenReturn(ResponseType.OK); - - final ArgumentCaptor<RequestResponseListener> captor = ArgumentCaptor.forClass(RequestResponseListener.class); - doNothing().when(request).addListener(captor.capture()); - - doAnswer(new Answer<Void>() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - Request req = (Request) invocation.getArguments()[0]; - assertSame(request, req); - - RequestResponseListener listener = captor.getValue(); - listener.fireComplete(request, response); - - return null; - } - - }).when(requestQueue).putRequest(request); - - ThreadCollector collector = new ThreadMXBeanCollector(context, reference) { - @Override - Request createRequest() { - return request; - } - }; - collector.setAgentInfoDao(agentDao); - collector.setThreadDao(threadDao); - collector.stopHarvester(); - - verify(request).setParameter(HarvesterCommand.class.getName(), HarvesterCommand.STOP.name()); - verify(request).setParameter(HarvesterCommand.VM_ID.name(), "00101010"); - - verify(requestQueue).putRequest(request); - } - - @Test - public void testStopNoRequestQueue() { - ThreadCollector collector = new ThreadMXBeanCollector(context, reference) { - @Override - Request createRequest() { - return request; - } - }; - collector.setAgentInfoDao(agentDao); - collector.setThreadDao(threadDao); - - boolean result = collector.stopHarvester(); - - verify(request).setParameter(HarvesterCommand.class.getName(), HarvesterCommand.STOP.name()); - verify(request).setParameter(HarvesterCommand.VM_ID.name(), "00101010"); - - assertFalse(result); - } -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-common/src/test/java/com/redhat/thermostat/thread/client/common/collector/internal/ThreadCollectorFactoryImplTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,77 @@ +/* + * Copyright 2012-2016 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.thread.client.common.collector.internal; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.mock; + +import org.junit.Test; + +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.testutils.StubBundleContext; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory; +import com.redhat.thermostat.thread.dao.ThreadDao; + +public class ThreadCollectorFactoryImplTest { + + @Test + public void testThreadCollectorFactory() { + StubBundleContext context = new StubBundleContext(); + VmRef reference = mock(VmRef.class); + + ThreadCollectorFactory factory = new ThreadCollectorFactoryImpl(context); + ThreadCollector collector = factory.getCollector(reference); + assertNotNull(collector); + } + + @Test + public void testThreadCollectorFactoryWithAgentAndThreadDaos() { + StubBundleContext context = new StubBundleContext(); + AgentInfoDAO agentDao = mock(AgentInfoDAO.class); + ThreadDao threadDao = mock(ThreadDao.class); + VmRef reference = mock(VmRef.class); + + ThreadCollectorFactory factory = new ThreadCollectorFactoryImpl(context); + factory.setAgentDao(agentDao); + factory.setThreadDao(threadDao); + ThreadCollector collector = factory.getCollector(reference); + assertNotNull(collector); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-common/src/test/java/com/redhat/thermostat/thread/client/common/collector/internal/ThreadCollectorTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,224 @@ +/* + * Copyright 2012-2016 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.thread.client.common.collector.internal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +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 org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import com.redhat.thermostat.client.command.RequestQueue; +import com.redhat.thermostat.common.command.Request; +import com.redhat.thermostat.common.command.RequestResponseListener; +import com.redhat.thermostat.common.command.Response; +import com.redhat.thermostat.common.command.Response.ResponseType; +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.testutils.StubBundleContext; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.collector.HarvesterCommand; +import com.redhat.thermostat.thread.dao.ThreadDao; +import com.redhat.thermostat.thread.model.ThreadHarvestingStatus; + +public class ThreadCollectorTest { + + private StubBundleContext context; + private ThreadDao threadDao; + private VmRef reference; + private Request request; + private AgentInfoDAO agentDao; + + @Before + public void setup() { + context = new StubBundleContext(); + request = mock(Request.class); + agentDao = mock(AgentInfoDAO.class); + threadDao = mock(ThreadDao.class); + reference = mock(VmRef.class); + when(reference.getVmId()).thenReturn("00101010"); + + final Response response = mock(Response.class); + when(response.getType()).thenReturn(ResponseType.OK); + + final ArgumentCaptor<RequestResponseListener> captor = ArgumentCaptor.forClass(RequestResponseListener.class); + doNothing().when(request).addListener(captor.capture()); + } + + @Test + public void testHarvesterCollecting() { + ThreadHarvestingStatus status = mock(ThreadHarvestingStatus.class); + when(status.isHarvesting()).thenReturn(true); + ThreadCollector collector = new ThreadMXBeanCollector(context, reference); + when(threadDao.getLatestHarvestingStatus(reference)).thenReturn(status); + + collector.setThreadDao(threadDao); + + assertTrue(collector.isHarvesterCollecting()); + } + + @Test + public void testStart() { + final RequestQueue requestQueue = mock(RequestQueue.class); + context.registerService(RequestQueue.class, requestQueue, null); + + final Response response = mock(Response.class); + when(response.getType()).thenReturn(ResponseType.OK); + + final ArgumentCaptor<RequestResponseListener> captor = ArgumentCaptor.forClass(RequestResponseListener.class); + doNothing().when(request).addListener(captor.capture()); + + doAnswer(new Answer<Void>() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + Request req = (Request) invocation.getArguments()[0]; + assertSame(request, req); + + RequestResponseListener listener = captor.getValue(); + listener.fireComplete(request, response); + + return null; + } + + }).when(requestQueue).putRequest(request); + + ThreadCollector collector = new ThreadMXBeanCollector(context, reference) { + @Override + Request createRequest() { + return request; + } + }; + collector.setAgentInfoDao(agentDao); + collector.setThreadDao(threadDao); + + collector.startHarvester(); + + verify(request).setParameter(HarvesterCommand.class.getName(), HarvesterCommand.START.name()); + verify(request).setParameter(HarvesterCommand.VM_ID.name(), "00101010"); + + verify(requestQueue).putRequest(request); + } + + @Test + public void testStartNoRequestQueue() { + ThreadCollector collector = new ThreadMXBeanCollector(context, reference) { + @Override + Request createRequest() { + return request; + } + }; + collector.setAgentInfoDao(agentDao); + collector.setThreadDao(threadDao); + + boolean result = collector.startHarvester(); + + verify(request).setParameter(HarvesterCommand.class.getName(), HarvesterCommand.START.name()); + verify(request).setParameter(HarvesterCommand.VM_ID.name(), "00101010"); + + assertFalse(result); + } + + @Test + public void testStop() { + final RequestQueue requestQueue = mock(RequestQueue.class); + context.registerService(RequestQueue.class, requestQueue, null); + + final Response response = mock(Response.class); + when(response.getType()).thenReturn(ResponseType.OK); + + final ArgumentCaptor<RequestResponseListener> captor = ArgumentCaptor.forClass(RequestResponseListener.class); + doNothing().when(request).addListener(captor.capture()); + + doAnswer(new Answer<Void>() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + Request req = (Request) invocation.getArguments()[0]; + assertSame(request, req); + + RequestResponseListener listener = captor.getValue(); + listener.fireComplete(request, response); + + return null; + } + + }).when(requestQueue).putRequest(request); + + ThreadCollector collector = new ThreadMXBeanCollector(context, reference) { + @Override + Request createRequest() { + return request; + } + }; + collector.setAgentInfoDao(agentDao); + collector.setThreadDao(threadDao); + collector.stopHarvester(); + + verify(request).setParameter(HarvesterCommand.class.getName(), HarvesterCommand.STOP.name()); + verify(request).setParameter(HarvesterCommand.VM_ID.name(), "00101010"); + + verify(requestQueue).putRequest(request); + } + + @Test + public void testStopNoRequestQueue() { + ThreadCollector collector = new ThreadMXBeanCollector(context, reference) { + @Override + Request createRequest() { + return request; + } + }; + collector.setAgentInfoDao(agentDao); + collector.setThreadDao(threadDao); + + boolean result = collector.stopHarvester(); + + verify(request).setParameter(HarvesterCommand.class.getName(), HarvesterCommand.STOP.name()); + verify(request).setParameter(HarvesterCommand.VM_ID.name(), "00101010"); + + assertFalse(result); + } +} +
--- a/thread/client-controllers/pom.xml Wed Apr 06 14:52:26 2016 +0200 +++ b/thread/client-controllers/pom.xml Fri Apr 08 13:18:48 2016 +0200 @@ -131,8 +131,8 @@ </Export-Package> <Private-Package> com.redhat.thermostat.thread.client.controller.osgi, - com.redhat.thermostat.thread.client.controller.impl, - com.redhat.thermostat.thread.client.controller.impl.cache, + com.redhat.thermostat.thread.client.controller.internal, + com.redhat.thermostat.thread.client.controller.internal.cache, </Private-Package> <!-- Do not autogenerate uses clauses in Manifests --> <_nouses>true</_nouses>
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/CommonController.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl; - -import com.redhat.thermostat.client.core.views.BasicView; -import com.redhat.thermostat.client.core.views.BasicView.Action; -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.Timer; -import com.redhat.thermostat.common.Timer.SchedulingType; -import com.redhat.thermostat.thread.model.SessionID; - -import java.util.concurrent.TimeUnit; - -public abstract class CommonController { - - protected Timer timer; - protected BasicView view; - - protected volatile SessionID session; - - public CommonController(Timer timer, BasicView view) { - this.view = view; - this.timer = timer; - } - - void initialize() { - timer.setInitialDelay(0); - timer.setDelay(1000); - timer.setTimeUnit(TimeUnit.MILLISECONDS); - timer.setSchedulingType(SchedulingType.FIXED_RATE); - - view.addActionListener(new ActionListener<Action>() { - @Override - public void actionPerformed(ActionEvent<Action> actionEvent) { - switch (actionEvent.getActionId()) { - case VISIBLE: - onViewVisible(); - timer.start(); - break; - - case HIDDEN: - timer.stop(); - onViewHidden(); - break; - - default: - break; - } - } - }); - } - - protected void onViewVisible() {} - protected void onViewHidden() {} - - public void setSession(SessionID session) { - this.session = session; - } -} -
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/LocaleResources.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl; - -import com.redhat.thermostat.shared.locale.Translate; - -public enum LocaleResources { - - CONTROLLER_NAME, - - WARNING_CANNOT_DISABLE, - WARNING_CANNOT_ENABLE, - - CHECKING_FOR_DEADLOCKS, - NO_DEADLOCK_DETECTED, - - STARTING_MONITORING, - STOPPING_MONITORING, - - LOADING_SESSION_LIST, - ; - - static final String RESOURCE_BUNDLE = "com.redhat.thermostat.thread.client.controller.impl.strings"; - - public static Translate<LocaleResources> createLocalizer() { - return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class); - } - -} -
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/LockController.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl; - -import com.redhat.thermostat.common.Timer; -import com.redhat.thermostat.storage.core.VmRef; -import com.redhat.thermostat.thread.client.common.view.LockView; -import com.redhat.thermostat.thread.dao.LockInfoDao; -import com.redhat.thermostat.thread.model.LockInfo; - -public class LockController extends CommonController { - - private LockInfoDao dao; - private VmRef vm; - - public LockController(LockView view, Timer timer, LockInfoDao lockInfoDao, VmRef vm) { - super(timer, view); - this.dao = lockInfoDao; - this.vm = vm; - timer.setAction(new LockInfoUpdateAction()); - } - - class LockInfoUpdateAction implements Runnable { - @Override - public void run() { - LockInfo result = dao.getLatestLockInfo(vm); - if (result != null) { - ((LockView) view).setLatestLockData(result); - } - } - } -}
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadCountController.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl; - -import com.redhat.thermostat.common.Timer; -import com.redhat.thermostat.common.model.Range; -import com.redhat.thermostat.thread.client.common.chart.LivingDaemonThreadDifferenceChart; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; -import com.redhat.thermostat.thread.client.common.view.ThreadCountView; -import com.redhat.thermostat.thread.model.ThreadSummary; - -import java.util.List; -import java.util.Objects; -import java.util.concurrent.TimeUnit; - -class ThreadCountController extends CommonController { - - private LivingDaemonThreadDifferenceChart model; - private ThreadCollector collector; - - public ThreadCountController(ThreadCountView view, ThreadCollector collector, Timer timer) { - super(timer, view); - - this.collector = collector; - model = new LivingDaemonThreadDifferenceChart("Living Threads vs. Daemon Threads", "time", "threads", - "Living Threads", "Daemon Threads"); - model.setMaximumItemCount(3600); - - timer.setAction(new ThreadInformationDataCollector()); - } - - class ThreadInformationDataCollector implements Runnable { - - private void updateLastSession() { - - ThreadCountView view = (ThreadCountView) ThreadCountController.this.view; - - // load the very latest thread summary - ThreadSummary latestSummary = collector.getLatestThreadSummary(); - Objects.requireNonNull(latestSummary); - - if (latestSummary.getTimeStamp() != 0) { - view.setLiveThreads(Long.toString(latestSummary.getCurrentLiveThreads())); - view.setDaemonThreads(Long.toString(latestSummary.getCurrentDaemonThreads())); - } - } - - private void updateChart() { - - ThreadCountView view = (ThreadCountView) ThreadCountController.this.view; - - long now = System.currentTimeMillis(); - long lastHour = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1); - - Range<Long> range = new Range<>(lastHour, now); - - boolean updateModel = false; - List<ThreadSummary> summaries = collector.getThreadSummary(range); - if (summaries.size() != 0) { - for (ThreadSummary summary : summaries) { - model.addData(summary.getTimeStamp(), summary.getCurrentLiveThreads(), summary.getCurrentDaemonThreads()); - } - updateModel = true; - } - - if (updateModel) { - view.updateLivingDaemonTimeline(model); - } - } - - @Override - public void run() { - updateLastSession(); - updateChart(); - } - } -} -
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationController.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,297 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl; - -import com.redhat.thermostat.client.core.controllers.InformationServiceController; -import com.redhat.thermostat.client.core.progress.ProgressHandle; -import com.redhat.thermostat.client.core.progress.ProgressNotifier; -import com.redhat.thermostat.client.core.views.UIComponent; -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.ApplicationService; -import com.redhat.thermostat.common.TimerFactory; -import com.redhat.thermostat.common.model.Range; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.shared.locale.LocalizedString; -import com.redhat.thermostat.shared.locale.Translate; -import com.redhat.thermostat.storage.core.VmRef; -import com.redhat.thermostat.storage.dao.VmInfoDAO; -import com.redhat.thermostat.thread.client.common.ThreadTableBean; -import com.redhat.thermostat.thread.client.common.ThreadViewProvider; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory; -import com.redhat.thermostat.thread.client.common.view.ThreadTableView; -import com.redhat.thermostat.thread.client.common.view.ThreadTableView.ThreadSelectionAction; -import com.redhat.thermostat.thread.client.common.view.ThreadView; -import com.redhat.thermostat.thread.client.common.view.ThreadView.ThreadAction; -import com.redhat.thermostat.thread.client.controller.impl.cache.AppCache; -import com.redhat.thermostat.thread.dao.LockInfoDao; -import com.redhat.thermostat.thread.model.SessionID; -import com.redhat.thermostat.thread.model.ThreadSession; - -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class ThreadInformationController implements InformationServiceController<VmRef> { - - private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); - - private VmRef ref; - private VmInfoDAO vmInfoDAO; - private LockInfoDao lockInfoDao; - - private static final Logger logger = LoggingUtils.getLogger(ThreadInformationController.class); - private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); - - private ThreadView view; - private ThreadCollector collector; - - private ApplicationService appService; - - private AppCache cache; - private ProgressNotifier notifier; - - private CommonController threadTimeline; - private CommonController threadTableController; - private CommonController threadCountController; - private VmDeadLockController deadLockController; - private CommonController lockTableController; - - public ThreadInformationController(VmRef ref, ApplicationService appService, - VmInfoDAO vmInfoDao, - LockInfoDao lockInfoDao, - ThreadCollectorFactory collectorFactory, - ThreadViewProvider viewFactory, - ProgressNotifier notifier) - { - this.appService = appService; - this.ref = ref; - this.notifier = notifier; - this.vmInfoDAO = vmInfoDao; - this.lockInfoDao = lockInfoDao; - - collector = collectorFactory.getCollector(ref); - - view = viewFactory.createView(); - view.setApplicationService(appService, ref.getVmId() + "-" + ref.getHostRef().getAgentId()); - - initControllers(); - - view.setRecording(isRecording() ? ThreadView.MonitoringState.STARTED : ThreadView.MonitoringState.STOPPED, false); - view.addThreadActionListener(new ThreadActionListener()); - - view.setEnableRecordingControl(vmInfoDao.getVmInfo(ref).isAlive()); - } - - private boolean isRecording() { - - return collector.isHarvesterCollecting(); - } - - @Override - public LocalizedString getLocalizedName() { - return t.localize(LocaleResources.CONTROLLER_NAME); - } - - @Override - public UIComponent getView() { - return view; - } - - private class ThreadActionListener implements ActionListener<ThreadAction> { - - @Override - public void actionPerformed(ActionEvent<ThreadAction> actionEvent) { - switch (actionEvent.getActionId()) { - case START_LIVE_RECORDING: - view.setRecording(ThreadView.MonitoringState.STARTING, false); - startHarvester(); - view.setRecording(ThreadView.MonitoringState.STARTED, false); - break; - - case STOP_LIVE_RECORDING: - view.setRecording(ThreadView.MonitoringState.STOPPING, false); - stopHarvester(); - view.setRecording(ThreadView.MonitoringState.STOPPED, false); - break; - - case REQUEST_DISPLAY_RECORDED_SESSIONS: - loadSessionsList(); - break; - - case REQUEST_LOAD_SESSION: { - ThreadSession session = (ThreadSession) actionEvent.getPayload(); - if (session != null) { - threadTimeline.setSession(session.getSessionID()); - threadTableController.setSession(session.getSessionID()); - } - } break; - - default: - logger.log(Level.WARNING, "unknown action: " + actionEvent.getActionId()); - break; - } - } - - private class SessionComparator implements Comparator<ThreadSession> { - @Override - public int compare(ThreadSession o1, ThreadSession o2) { - // TODO: descending order only for now, we should allow the users - // to sort this via the UI though - int result = Long.compare(o1.getTimeStamp(), o2.getTimeStamp()); - return -result; - } - } - - private void loadSessionsList() { - submitTask(new Runnable() { - @Override - public void run() { - Range<Long> range = new Range<>(0L, System.currentTimeMillis()); - List<ThreadSession> threadSessions = collector.getThreadSessions(range); - - Collections.sort(threadSessions, new SessionComparator()); - view.displayTimelineSessionList(threadSessions); - - } - }, translator.localize(LocaleResources.LOADING_SESSION_LIST)); - } - - private void startHarvester() { - submitTask(new Runnable() { - @Override - public void run() { - boolean result = collector.startHarvester(); - if (!result) { - view.displayWarning(t.localize(LocaleResources.WARNING_CANNOT_ENABLE)); - view.setEnableRecordingControl(false); - view.setRecording(ThreadView.MonitoringState.DISABLED, false); - } - } - }, translator.localize(LocaleResources.STARTING_MONITORING)); - } - - private void stopHarvester() { - submitTask(new Runnable() { - @Override - public void run() { - boolean result = collector.stopHarvester(); - if (!result) { - view.displayWarning(t.localize(LocaleResources.WARNING_CANNOT_DISABLE)); - view.setEnableRecordingControl(false); - view.setRecording(ThreadView.MonitoringState.DISABLED, false); - } - } - }, translator.localize(LocaleResources.STOPPING_MONITORING)); - } - - private void submitTask(final Runnable task, final LocalizedString taskName) { - appService.getApplicationExecutor().execute(new Runnable() { - @Override - public void run() { - final ProgressHandle handle = new ProgressHandle(taskName); - handle.setTask(taskName); - handle.setIndeterminate(true); - notifier.register(handle); - handle.runTask(task); - } - }); - } - } - - private class ThreadSelectionActionListener implements ActionListener<ThreadSelectionAction> { - @Override - public void actionPerformed(ActionEvent<ThreadSelectionAction> actionEvent) { - view.displayThreadDetails((ThreadTableBean) actionEvent.getPayload()); - } - } - - void ___injectControllersForTesting(ThreadTimelineController timeline, - ThreadTableController table, - ThreadCountController count, - LockController lock, - VmDeadLockController deadLock) - { - this.threadTableController = table; - this.threadCountController = count; - this.deadLockController = deadLock; - this.threadTimeline = timeline; - this.lockTableController = lock; - } - - void ___injectCollectorForTesting(ThreadCollector collector) { - this.collector = collector; - } - - private void initControllers() { - TimerFactory tf = appService.getTimerFactory(); - - deadLockController = - new VmDeadLockController(vmInfoDAO, ref, view.createDeadLockView(), collector, tf.createTimer(), - appService.getApplicationExecutor(), notifier); - deadLockController.initialize(); - - ThreadTableView threadTableView = view.createThreadTableView(); - threadTableView.addThreadSelectionActionListener(new ThreadSelectionActionListener()); - - threadCountController = - new ThreadCountController(view.createThreadCountView(), collector, tf.createTimer()); - threadCountController.initialize(); - - threadTableController = - new ThreadTableController(threadTableView, collector, tf.createTimer()); - threadTableController.initialize(); - - threadTimeline = new ThreadTimelineController(view.createThreadTimelineView(), - collector, - tf.createTimer()); - threadTimeline.initialize(); - SessionID lastThreadSession = collector.getLastThreadSession(); - threadTimeline.setSession(lastThreadSession); - - lockTableController = - new LockController(view.createLockView(), - tf.createTimer(), - lockInfoDao, - ref); - lockTableController.initialize(); - } -} -
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationServiceImpl.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl; - -import com.redhat.thermostat.client.core.NameMatchingRefFilter; -import com.redhat.thermostat.client.core.controllers.InformationServiceController; -import com.redhat.thermostat.client.core.progress.ProgressNotifier; -import com.redhat.thermostat.common.ApplicationCache; -import com.redhat.thermostat.common.ApplicationService; -import com.redhat.thermostat.common.Filter; -import com.redhat.thermostat.storage.core.VmRef; -import com.redhat.thermostat.storage.dao.VmInfoDAO; -import com.redhat.thermostat.thread.client.common.ThreadViewProvider; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory; -import com.redhat.thermostat.thread.client.controller.ThreadInformationService; -import com.redhat.thermostat.thread.client.controller.impl.cache.AppCache; -import com.redhat.thermostat.thread.client.controller.impl.cache.AppCacheKey; -import com.redhat.thermostat.thread.dao.LockInfoDao; - -public class ThreadInformationServiceImpl implements ThreadInformationService { - - private static final int ORDER = ORDER_THREAD_GROUP; - - private Filter<VmRef> filter = new NameMatchingRefFilter<>(); - private ApplicationService service; - private VmInfoDAO vmInfoDao; - private LockInfoDao lockInfoDao; - private ThreadCollectorFactory collectorFactory; - private ThreadViewProvider viewFactory; - private ProgressNotifier notifier; - - public ThreadInformationServiceImpl(ApplicationService appService, - VmInfoDAO vmInfoDao, - LockInfoDao lockInfoDao, - ThreadCollectorFactory collectorFactory, - ThreadViewProvider viewFactory, ProgressNotifier notifier) - { - this.service = appService; - this.vmInfoDao = vmInfoDao; - this.lockInfoDao = lockInfoDao; - this.collectorFactory = collectorFactory; - this.viewFactory = viewFactory; - this.notifier = notifier; - } - - @Override - public Filter<VmRef> getFilter() { - return filter; - } - - private AppCache getCache(VmRef ref) { - ApplicationCache applicationCache = service.getApplicationCache(); - AppCache cache = (AppCache) applicationCache.getAttribute(ref.getVmId()); - if (cache == null) { - AppCacheKey mainKey = new AppCacheKey(ref.getVmId(), ThreadInformationController.class); - cache = new AppCache(mainKey, applicationCache); - applicationCache.addAttribute(ref.getVmId(), cache); - } - return cache; - } - - @Override - public InformationServiceController<VmRef> getInformationServiceController(VmRef ref) { - AppCache cache = getCache(ref); - AppCacheKey key = new AppCacheKey(ref.getVmId(), ThreadInformationController.class); - ThreadInformationController controller = cache.retrieve(key); - if (controller == null) { - controller = new ThreadInformationController(ref, service, - vmInfoDao, - lockInfoDao, - collectorFactory, - viewFactory, - notifier); - cache.save(key, controller); - } - return controller; - } - - @Override - public int getOrderValue() { - return ORDER; - } - -} -
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTableController.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,218 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl; - -import com.redhat.thermostat.common.Timer; -import com.redhat.thermostat.common.model.Range; -import com.redhat.thermostat.storage.core.experimental.statement.ResultHandler; -import com.redhat.thermostat.thread.client.common.ThreadTableBean; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; -import com.redhat.thermostat.thread.client.common.model.timeline.ThreadInfo; -import com.redhat.thermostat.thread.client.common.view.ThreadTableView; -import com.redhat.thermostat.thread.model.SessionID; -import com.redhat.thermostat.thread.model.ThreadState; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -public class ThreadTableController extends CommonController { - - private ThreadTableView threadTableView; - private ThreadCollector collector; - - private volatile boolean stopLooping; - - public ThreadTableController(ThreadTableView threadTableView, - ThreadCollector collector, - Timer timer) - { - super(timer, threadTableView); - this.threadTableView = threadTableView; - this.collector = collector; - timer.setAction(new ThreadTableControllerAction()); - } - - @Override - protected void onViewVisible() { - stopLooping = false; - } - - @Override - protected void onViewHidden() { - stopLooping = true; - } - - private class ThreadTableControllerAction implements Runnable { - - private ThreadResultHandler handler; - private Range<Long> range; - private SessionID lastSession; - private long lastUpdate; - - public ThreadTableControllerAction() { - handler = new ThreadResultHandler(); - resetState(); - } - - private void resetState() { - handler.threadStates.clear(); - threadTableView.clear(); - range = null; - lastUpdate = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1); - } - - @Override - public void run() { - SessionID session = ThreadTableController.this.session; - if (session == null) { - // no session selected, but let's try to default to the last - // available - session = collector.getLastThreadSession(); - if (session == null) { - // ok, really no data, let's skip this round - return; - } - } - - if (lastSession == null || - !session.get().equals(lastSession.get())) { - // since we only visualise one session at a time and this is - // a new session, let's clear the view - resetState(); - } - lastSession = session; - - // get the full range of known timelines per vm - Range<Long> totalRange = collector.getThreadRange(session); - if (totalRange == null) { - // this just means we don't have any data yet - return; - } - - range = new Range<>(lastUpdate, totalRange.getMax()); - lastUpdate = totalRange.getMax(); - - collector.getThreadStates(session, - handler, - range); - threadTableView.submitChanges(); - } - } - - private class ThreadResultHandler implements ResultHandler<ThreadState> { - private Map<ThreadInfo, ThreadTableBean> threadStates; - - public ThreadResultHandler() { - this.threadStates = new HashMap<>(); - } - - @Override - public boolean onResult(ThreadState thread) { - - ThreadInfo key = new ThreadInfo(); - key.setName(thread.getName()); - key.setId(thread.getId()); - - ThreadTableBean bean = threadStates.get(key); - if (bean == null) { - bean = new ThreadTableBean(); - bean.setName(thread.getName()); - bean.setId(thread.getId()); - bean.setStartTimeStamp(thread.getTimeStamp()); - threadStates.put(key, bean); - } - - setCurrentStateTime(bean, thread); - - double totalRunningTime = bean.getRunningTime() + - bean.getMonitorTime() + - bean.getSleepingTime() + - bean.getWaitingTime(); - if (totalRunningTime > 0) { - double percent = (bean.getRunningTime() / totalRunningTime) * 100; - bean.setRunningPercent(percent); - - percent = (bean.getWaitingTime() / totalRunningTime) * 100; - bean.setWaitingPercent(percent); - - percent = (bean.getMonitorTime() / totalRunningTime) * 100; - bean.setMonitorPercent(percent); - - percent = (bean.getSleepingTime() / totalRunningTime) * 100; - bean.setSleepingPercent(percent); - } - - bean.setBlockedCount(thread.getBlockedCount()); - bean.setWaitedCount(thread.getWaitedCount()); - - bean.setStopTimeStamp(thread.getTimeStamp()); - - threadTableView.display(bean); - - boolean _stopLooping = stopLooping; - return !_stopLooping; - } - } - - void setCurrentStateTime(ThreadTableBean bean, ThreadState thread) { - Thread.State threadState = Thread.State.valueOf(thread.getState()); - - switch (threadState) { - case RUNNABLE: - bean.setRunningTime(bean.getRunningTime() + 1); - break; - - case BLOCKED: - bean.setMonitorTime(bean.getMonitorTime() + 1); - break; - - case TIMED_WAITING: - bean.setSleepingTime(bean.getSleepingTime() + 1); - break; - - case WAITING: - bean.setWaitingTime(bean.getWaitingTime() + 1); - break; - - case NEW: - case TERMINATED: - default: - break; - } - } -} -
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTimelineController.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,178 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl; - -import com.redhat.thermostat.common.Timer; -import com.redhat.thermostat.common.model.Range; -import com.redhat.thermostat.storage.core.experimental.statement.ResultHandler; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; -import com.redhat.thermostat.thread.client.common.model.timeline.ThreadInfo; -import com.redhat.thermostat.thread.client.common.model.timeline.TimelineFactory; -import com.redhat.thermostat.thread.client.common.model.timeline.TimelineProbe; -import com.redhat.thermostat.thread.client.common.view.ThreadTimelineView; -import com.redhat.thermostat.thread.model.SessionID; -import com.redhat.thermostat.thread.model.ThreadState; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -public class ThreadTimelineController extends CommonController { - - private static final boolean _DEBUG_BLOCK_TIMING_ = false; - - private ThreadTimelineView view; - private ThreadCollector collector; - - private volatile boolean stopLooping; - - public ThreadTimelineController(ThreadTimelineView view, - ThreadCollector collector, - Timer timer) - { - super(timer, view); - this.view = view; - this.collector = collector; - - timer.setAction(new ThreadTimelineControllerAction()); - } - - private class ThreadTimelineControllerAction implements Runnable { - - private Range<Long> range; - private Range<Long> lastRange; - private ThreadStateResultHandler threadStateResultHandler; - private long lastUpdate; - - private SessionID lastSession; - - public ThreadTimelineControllerAction() { - lastUpdate = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1); - threadStateResultHandler = new ThreadStateResultHandler(); - } - - private void resetState() { - view.clear(); - lastRange = null; - lastUpdate = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1); - threadStateResultHandler.knownStates.clear(); - threadStateResultHandler.key = new ThreadInfo(); - } - - @Override - public void run() { - SessionID session = ThreadTimelineController.this.session; - if (session == null) { - // no session selected, but let's try to default to the last - // available - session = collector.getLastThreadSession(); - if (session == null) { - // ok, really no data, let's skip this round - return; - } - } - - if (lastSession == null || - !session.get().equals(lastSession.get())) - { - // since we only visualise one session at a time and this is - // a new session, let's clear the view - resetState(); - } - lastSession = session; - - // get the full range of known timelines per vm - Range<Long> totalRange = collector.getThreadRange(session); - if (totalRange == null) { - // this just means we don't have any data yet - return; - } - - if (!totalRange.equals(lastRange)) { - view.setTotalRange(totalRange); - } - lastRange = totalRange; - - range = new Range<>(lastUpdate, totalRange.getMax()); - lastUpdate = totalRange.getMax(); - - collector.getThreadStates(session, - threadStateResultHandler, - range); - } - } - - @Override - protected void onViewVisible() { - stopLooping = false; - } - - @Override - protected void onViewHidden() { - stopLooping = true; - } - - private class ThreadStateResultHandler implements ResultHandler<ThreadState> { - private ThreadInfo key; - private Set<ThreadInfo> knownStates; - - public ThreadStateResultHandler() { - this.key = new ThreadInfo(); - knownStates = new HashSet<>(); - } - - @Override - public boolean onResult(ThreadState state) { - - key.setName(state.getName()); - key.setId(state.getId()); - - ThreadInfo info = new ThreadInfo(key); - if (!knownStates.contains(key)) { - view.addThread(info); - knownStates.add(info); - } - - TimelineProbe probe = TimelineFactory.createTimelineProbe(state); - view.addProbe(info, probe); - - boolean _stopLooping = stopLooping; - return !_stopLooping; - } - } -} -
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/VmDeadLockController.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,204 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.StringReader; -import java.util.Objects; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.client.core.progress.ProgressHandle; -import com.redhat.thermostat.client.core.progress.ProgressNotifier; -import com.redhat.thermostat.client.core.views.BasicView.Action; -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.Timer; -import com.redhat.thermostat.common.Timer.SchedulingType; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.shared.locale.LocalizedString; -import com.redhat.thermostat.shared.locale.Translate; -import com.redhat.thermostat.storage.core.VmRef; -import com.redhat.thermostat.storage.dao.VmInfoDAO; -import com.redhat.thermostat.thread.client.common.DeadlockParser; -import com.redhat.thermostat.thread.client.common.DeadlockParser.Information; -import com.redhat.thermostat.thread.client.common.DeadlockParser.ParseException; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; -import com.redhat.thermostat.thread.client.common.view.VmDeadLockView; -import com.redhat.thermostat.thread.client.common.view.VmDeadLockView.VmDeadLockViewAction; -import com.redhat.thermostat.thread.model.VmDeadLockData; - -public class VmDeadLockController { - - private static final Logger logger = LoggingUtils.getLogger(VmDeadLockController.class); - private static final Translate<LocaleResources> translate = LocaleResources.createLocalizer(); - - private static final String NO_DEADLOCK = translate.localize(LocaleResources.NO_DEADLOCK_DETECTED).getContents(); - - private VmInfoDAO vmInfoDAO; - private VmRef vmRef; - - private VmDeadLockView view; - private ThreadCollector collector; - private Timer timer; - private ExecutorService executor; - private ProgressNotifier notifier; - - private final AtomicReference<String> descriptionRef = new AtomicReference<>(""); - private String previousDeadlockData = null; - - - public VmDeadLockController(VmInfoDAO vmInfoDAO, VmRef vmRef, VmDeadLockView view, ThreadCollector collector, Timer timer, - ExecutorService executor, ProgressNotifier notifier) { - this.vmInfoDAO = vmInfoDAO; - this.vmRef = vmRef; - this.view = view; - this.collector = collector; - this.timer = timer; - this.executor = executor; - this.notifier = Objects.requireNonNull(notifier); - } - - public void initialize() { - view.addVmDeadLockViewActionListener(new ActionListener<VmDeadLockViewAction>() { - @Override - public void actionPerformed(ActionEvent<VmDeadLockViewAction> actionEvent) { - switch (actionEvent.getActionId()) { - case CHECK_FOR_DEADLOCK: - executor.execute(new Runnable() { - @Override - public void run() { - LocalizedString message = translate.localize(LocaleResources.CHECKING_FOR_DEADLOCKS); - ProgressHandle handle = new ProgressHandle(message); - handle.setIndeterminate(true); - - notifier.register(handle); - - handle.runTask(new Runnable() { - @Override - public void run() { - checkForDeadLock(); - updateViewIfNeeded(); - } - }); - } - }); - break; - default: - break; - } - } - }); - - timer.setAction(new Runnable() { - @Override - public void run() { - checkStorageForDeadLockData(); - updateViewIfNeeded(); - } - }); - timer.setDelay(5); - timer.setInitialDelay(0); - timer.setTimeUnit(TimeUnit.SECONDS); - timer.setSchedulingType(SchedulingType.FIXED_DELAY); - - view.addActionListener(new ActionListener<Action>() { - @Override - public void actionPerformed(ActionEvent<Action> actionEvent) { - switch (actionEvent.getActionId()) { - case HIDDEN: - timer.stop(); - break; - case VISIBLE: - timer.start(); - break; - } - } - }); - - view.setCheckDeadlockControlEnabled(vmInfoDAO.getVmInfo(vmRef).isAlive()); - } - - private void checkForDeadLock() { - askAgentToCheckForDeadLock(); - checkStorageForDeadLockData(); - } - - private void askAgentToCheckForDeadLock() { - collector.requestDeadLockCheck(); - } - - private void checkStorageForDeadLockData() { - VmDeadLockData data = collector.getLatestDeadLockData(); - if (data == null) { - // no deadlock data; so don't update anything - return; - } - - String description = data.getDeadLockDescription(); - if (description.equals(VmDeadLockData.NO_DEADLOCK)) { - description = NO_DEADLOCK; - } - this.descriptionRef.set(description); - - } - - private void updateViewIfNeeded() { - String rawDeadlockData = descriptionRef.get(); - - if (!rawDeadlockData.equals(previousDeadlockData)) { - Information parsed = null; - - if (!rawDeadlockData.equals(NO_DEADLOCK)) { - try { - parsed = new DeadlockParser().parse(new BufferedReader(new StringReader(rawDeadlockData))); - } catch (IOException | ParseException e) { - logger.log(Level.FINE, "Failed to parse deadlock data. Visualizations might not show up correctly.", e); - } - } - - view.setDeadLockInformation(parsed, rawDeadlockData); - previousDeadlockData = rawDeadlockData; - } - } - -} -
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/cache/AppCache.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl.cache; - -import com.redhat.thermostat.common.ApplicationCache; -import java.util.HashMap; - -/** - * - */ -public class AppCache { - private static final String LOCK = new String("AppCacheLock"); - - private AppCacheKey root; - private ApplicationCache cache; - - public AppCache(AppCacheKey root, ApplicationCache cache) { - this.root = root; - this.cache = cache; - } - - public <E> void save(AppCacheKey key, E value) { - synchronized (LOCK) { - HashMap<AppCacheKey, E> localCache = getLocalCache(); - localCache.put(key, value); - saveLocalCache(localCache); - } - } - - public <E> E retrieve(AppCacheKey key) { - synchronized (LOCK) { - HashMap<AppCacheKey, E> localCache = getLocalCache(); - return localCache.get(key); - } - } - - private <E> HashMap<AppCacheKey, E> getLocalCache() { - HashMap<AppCacheKey, E> localCache = - (HashMap<AppCacheKey, E>) cache.getAttribute(root); - - if (localCache == null) { - localCache = new HashMap<>(); - saveLocalCache(localCache); - } - - return localCache; - } - - private <E> void saveLocalCache(HashMap<AppCacheKey, E> localCache) { - cache.addAttribute(root, localCache); - } -}
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/cache/AppCacheKey.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl.cache; - -import java.util.Objects; - -/** - * - */ -public class AppCacheKey { - private String UUID; - private String targetClass; - - public AppCacheKey(Class<?> hostClass, Class<?> targetClass) { - this(hostClass.getSimpleName(), targetClass.getSimpleName()); - } - - public AppCacheKey(String UUID, Class<?> targetClass) { - this(UUID, targetClass.getSimpleName()); - } - - private AppCacheKey(String UUID, String targetClass) { - this.UUID = UUID; - this.targetClass = targetClass; - Objects.requireNonNull(UUID); - Objects.requireNonNull(targetClass); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - AppCacheKey that = (AppCacheKey) o; - - if (!UUID.equals(that.UUID)) return false; - if (!targetClass.equals(that.targetClass)) return false; - - return true; - } - - @Override - public int hashCode() { - int result = UUID.hashCode(); - result = 31 * result + targetClass.hashCode(); - return result; - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/internal/CommonController.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,95 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal; + +import com.redhat.thermostat.client.core.views.BasicView; +import com.redhat.thermostat.client.core.views.BasicView.Action; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.Timer.SchedulingType; +import com.redhat.thermostat.thread.model.SessionID; + +import java.util.concurrent.TimeUnit; + +public abstract class CommonController { + + protected Timer timer; + protected BasicView view; + + protected volatile SessionID session; + + public CommonController(Timer timer, BasicView view) { + this.view = view; + this.timer = timer; + } + + void initialize() { + timer.setInitialDelay(0); + timer.setDelay(1000); + timer.setTimeUnit(TimeUnit.MILLISECONDS); + timer.setSchedulingType(SchedulingType.FIXED_RATE); + + view.addActionListener(new ActionListener<Action>() { + @Override + public void actionPerformed(ActionEvent<Action> actionEvent) { + switch (actionEvent.getActionId()) { + case VISIBLE: + onViewVisible(); + timer.start(); + break; + + case HIDDEN: + timer.stop(); + onViewHidden(); + break; + + default: + break; + } + } + }); + } + + protected void onViewVisible() {} + protected void onViewHidden() {} + + public void setSession(SessionID session) { + this.session = session; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/internal/LocaleResources.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal; + +import com.redhat.thermostat.shared.locale.Translate; + +public enum LocaleResources { + + CONTROLLER_NAME, + + WARNING_CANNOT_DISABLE, + WARNING_CANNOT_ENABLE, + + CHECKING_FOR_DEADLOCKS, + NO_DEADLOCK_DETECTED, + + STARTING_MONITORING, + STOPPING_MONITORING, + + LOADING_SESSION_LIST, + ; + + static final String RESOURCE_BUNDLE = "com.redhat.thermostat.thread.client.controller.internal.strings"; + + public static Translate<LocaleResources> createLocalizer() { + return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class); + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/internal/LockController.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,66 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal; + +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.thread.client.common.view.LockView; +import com.redhat.thermostat.thread.dao.LockInfoDao; +import com.redhat.thermostat.thread.model.LockInfo; + +public class LockController extends CommonController { + + private LockInfoDao dao; + private VmRef vm; + + public LockController(LockView view, Timer timer, LockInfoDao lockInfoDao, VmRef vm) { + super(timer, view); + this.dao = lockInfoDao; + this.vm = vm; + timer.setAction(new LockInfoUpdateAction()); + } + + class LockInfoUpdateAction implements Runnable { + @Override + public void run() { + LockInfo result = dao.getLatestLockInfo(vm); + if (result != null) { + ((LockView) view).setLatestLockData(result); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/internal/ThreadCountController.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,112 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal; + +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.thread.client.common.chart.LivingDaemonThreadDifferenceChart; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.client.common.view.ThreadCountView; +import com.redhat.thermostat.thread.model.ThreadSummary; + +import java.util.List; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +class ThreadCountController extends CommonController { + + private LivingDaemonThreadDifferenceChart model; + private ThreadCollector collector; + + public ThreadCountController(ThreadCountView view, ThreadCollector collector, Timer timer) { + super(timer, view); + + this.collector = collector; + model = new LivingDaemonThreadDifferenceChart("Living Threads vs. Daemon Threads", "time", "threads", + "Living Threads", "Daemon Threads"); + model.setMaximumItemCount(3600); + + timer.setAction(new ThreadInformationDataCollector()); + } + + class ThreadInformationDataCollector implements Runnable { + + private void updateLastSession() { + + ThreadCountView view = (ThreadCountView) ThreadCountController.this.view; + + // load the very latest thread summary + ThreadSummary latestSummary = collector.getLatestThreadSummary(); + Objects.requireNonNull(latestSummary); + + if (latestSummary.getTimeStamp() != 0) { + view.setLiveThreads(Long.toString(latestSummary.getCurrentLiveThreads())); + view.setDaemonThreads(Long.toString(latestSummary.getCurrentDaemonThreads())); + } + } + + private void updateChart() { + + ThreadCountView view = (ThreadCountView) ThreadCountController.this.view; + + long now = System.currentTimeMillis(); + long lastHour = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1); + + Range<Long> range = new Range<>(lastHour, now); + + boolean updateModel = false; + List<ThreadSummary> summaries = collector.getThreadSummary(range); + if (summaries.size() != 0) { + for (ThreadSummary summary : summaries) { + model.addData(summary.getTimeStamp(), summary.getCurrentLiveThreads(), summary.getCurrentDaemonThreads()); + } + updateModel = true; + } + + if (updateModel) { + view.updateLivingDaemonTimeline(model); + } + } + + @Override + public void run() { + updateLastSession(); + updateChart(); + } + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/internal/ThreadInformationController.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,297 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal; + +import com.redhat.thermostat.client.core.controllers.InformationServiceController; +import com.redhat.thermostat.client.core.progress.ProgressHandle; +import com.redhat.thermostat.client.core.progress.ProgressNotifier; +import com.redhat.thermostat.client.core.views.UIComponent; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.common.TimerFactory; +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.shared.locale.LocalizedString; +import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.dao.VmInfoDAO; +import com.redhat.thermostat.thread.client.common.ThreadTableBean; +import com.redhat.thermostat.thread.client.common.ThreadViewProvider; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory; +import com.redhat.thermostat.thread.client.common.view.ThreadTableView; +import com.redhat.thermostat.thread.client.common.view.ThreadTableView.ThreadSelectionAction; +import com.redhat.thermostat.thread.client.common.view.ThreadView; +import com.redhat.thermostat.thread.client.common.view.ThreadView.ThreadAction; +import com.redhat.thermostat.thread.client.controller.internal.cache.AppCache; +import com.redhat.thermostat.thread.dao.LockInfoDao; +import com.redhat.thermostat.thread.model.SessionID; +import com.redhat.thermostat.thread.model.ThreadSession; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class ThreadInformationController implements InformationServiceController<VmRef> { + + private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + + private VmRef ref; + private VmInfoDAO vmInfoDAO; + private LockInfoDao lockInfoDao; + + private static final Logger logger = LoggingUtils.getLogger(ThreadInformationController.class); + private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); + + private ThreadView view; + private ThreadCollector collector; + + private ApplicationService appService; + + private AppCache cache; + private ProgressNotifier notifier; + + private CommonController threadTimeline; + private CommonController threadTableController; + private CommonController threadCountController; + private VmDeadLockController deadLockController; + private CommonController lockTableController; + + public ThreadInformationController(VmRef ref, ApplicationService appService, + VmInfoDAO vmInfoDao, + LockInfoDao lockInfoDao, + ThreadCollectorFactory collectorFactory, + ThreadViewProvider viewFactory, + ProgressNotifier notifier) + { + this.appService = appService; + this.ref = ref; + this.notifier = notifier; + this.vmInfoDAO = vmInfoDao; + this.lockInfoDao = lockInfoDao; + + collector = collectorFactory.getCollector(ref); + + view = viewFactory.createView(); + view.setApplicationService(appService, ref.getVmId() + "-" + ref.getHostRef().getAgentId()); + + initControllers(); + + view.setRecording(isRecording() ? ThreadView.MonitoringState.STARTED : ThreadView.MonitoringState.STOPPED, false); + view.addThreadActionListener(new ThreadActionListener()); + + view.setEnableRecordingControl(vmInfoDao.getVmInfo(ref).isAlive()); + } + + private boolean isRecording() { + + return collector.isHarvesterCollecting(); + } + + @Override + public LocalizedString getLocalizedName() { + return t.localize(LocaleResources.CONTROLLER_NAME); + } + + @Override + public UIComponent getView() { + return view; + } + + private class ThreadActionListener implements ActionListener<ThreadAction> { + + @Override + public void actionPerformed(ActionEvent<ThreadAction> actionEvent) { + switch (actionEvent.getActionId()) { + case START_LIVE_RECORDING: + view.setRecording(ThreadView.MonitoringState.STARTING, false); + startHarvester(); + view.setRecording(ThreadView.MonitoringState.STARTED, false); + break; + + case STOP_LIVE_RECORDING: + view.setRecording(ThreadView.MonitoringState.STOPPING, false); + stopHarvester(); + view.setRecording(ThreadView.MonitoringState.STOPPED, false); + break; + + case REQUEST_DISPLAY_RECORDED_SESSIONS: + loadSessionsList(); + break; + + case REQUEST_LOAD_SESSION: { + ThreadSession session = (ThreadSession) actionEvent.getPayload(); + if (session != null) { + threadTimeline.setSession(session.getSessionID()); + threadTableController.setSession(session.getSessionID()); + } + } break; + + default: + logger.log(Level.WARNING, "unknown action: " + actionEvent.getActionId()); + break; + } + } + + private class SessionComparator implements Comparator<ThreadSession> { + @Override + public int compare(ThreadSession o1, ThreadSession o2) { + // TODO: descending order only for now, we should allow the users + // to sort this via the UI though + int result = Long.compare(o1.getTimeStamp(), o2.getTimeStamp()); + return -result; + } + } + + private void loadSessionsList() { + submitTask(new Runnable() { + @Override + public void run() { + Range<Long> range = new Range<>(0L, System.currentTimeMillis()); + List<ThreadSession> threadSessions = collector.getThreadSessions(range); + + Collections.sort(threadSessions, new SessionComparator()); + view.displayTimelineSessionList(threadSessions); + + } + }, translator.localize(LocaleResources.LOADING_SESSION_LIST)); + } + + private void startHarvester() { + submitTask(new Runnable() { + @Override + public void run() { + boolean result = collector.startHarvester(); + if (!result) { + view.displayWarning(t.localize(LocaleResources.WARNING_CANNOT_ENABLE)); + view.setEnableRecordingControl(false); + view.setRecording(ThreadView.MonitoringState.DISABLED, false); + } + } + }, translator.localize(LocaleResources.STARTING_MONITORING)); + } + + private void stopHarvester() { + submitTask(new Runnable() { + @Override + public void run() { + boolean result = collector.stopHarvester(); + if (!result) { + view.displayWarning(t.localize(LocaleResources.WARNING_CANNOT_DISABLE)); + view.setEnableRecordingControl(false); + view.setRecording(ThreadView.MonitoringState.DISABLED, false); + } + } + }, translator.localize(LocaleResources.STOPPING_MONITORING)); + } + + private void submitTask(final Runnable task, final LocalizedString taskName) { + appService.getApplicationExecutor().execute(new Runnable() { + @Override + public void run() { + final ProgressHandle handle = new ProgressHandle(taskName); + handle.setTask(taskName); + handle.setIndeterminate(true); + notifier.register(handle); + handle.runTask(task); + } + }); + } + } + + private class ThreadSelectionActionListener implements ActionListener<ThreadSelectionAction> { + @Override + public void actionPerformed(ActionEvent<ThreadSelectionAction> actionEvent) { + view.displayThreadDetails((ThreadTableBean) actionEvent.getPayload()); + } + } + + void ___injectControllersForTesting(ThreadTimelineController timeline, + ThreadTableController table, + ThreadCountController count, + LockController lock, + VmDeadLockController deadLock) + { + this.threadTableController = table; + this.threadCountController = count; + this.deadLockController = deadLock; + this.threadTimeline = timeline; + this.lockTableController = lock; + } + + void ___injectCollectorForTesting(ThreadCollector collector) { + this.collector = collector; + } + + private void initControllers() { + TimerFactory tf = appService.getTimerFactory(); + + deadLockController = + new VmDeadLockController(vmInfoDAO, ref, view.createDeadLockView(), collector, tf.createTimer(), + appService.getApplicationExecutor(), notifier); + deadLockController.initialize(); + + ThreadTableView threadTableView = view.createThreadTableView(); + threadTableView.addThreadSelectionActionListener(new ThreadSelectionActionListener()); + + threadCountController = + new ThreadCountController(view.createThreadCountView(), collector, tf.createTimer()); + threadCountController.initialize(); + + threadTableController = + new ThreadTableController(threadTableView, collector, tf.createTimer()); + threadTableController.initialize(); + + threadTimeline = new ThreadTimelineController(view.createThreadTimelineView(), + collector, + tf.createTimer()); + threadTimeline.initialize(); + SessionID lastThreadSession = collector.getLastThreadSession(); + threadTimeline.setSession(lastThreadSession); + + lockTableController = + new LockController(view.createLockView(), + tf.createTimer(), + lockInfoDao, + ref); + lockTableController.initialize(); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/internal/ThreadInformationServiceImpl.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,119 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal; + +import com.redhat.thermostat.client.core.NameMatchingRefFilter; +import com.redhat.thermostat.client.core.controllers.InformationServiceController; +import com.redhat.thermostat.client.core.progress.ProgressNotifier; +import com.redhat.thermostat.common.ApplicationCache; +import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.common.Filter; +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.dao.VmInfoDAO; +import com.redhat.thermostat.thread.client.common.ThreadViewProvider; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory; +import com.redhat.thermostat.thread.client.controller.ThreadInformationService; +import com.redhat.thermostat.thread.client.controller.internal.cache.AppCache; +import com.redhat.thermostat.thread.client.controller.internal.cache.AppCacheKey; +import com.redhat.thermostat.thread.dao.LockInfoDao; + +public class ThreadInformationServiceImpl implements ThreadInformationService { + + private static final int ORDER = ORDER_THREAD_GROUP; + + private Filter<VmRef> filter = new NameMatchingRefFilter<>(); + private ApplicationService service; + private VmInfoDAO vmInfoDao; + private LockInfoDao lockInfoDao; + private ThreadCollectorFactory collectorFactory; + private ThreadViewProvider viewFactory; + private ProgressNotifier notifier; + + public ThreadInformationServiceImpl(ApplicationService appService, + VmInfoDAO vmInfoDao, + LockInfoDao lockInfoDao, + ThreadCollectorFactory collectorFactory, + ThreadViewProvider viewFactory, ProgressNotifier notifier) + { + this.service = appService; + this.vmInfoDao = vmInfoDao; + this.lockInfoDao = lockInfoDao; + this.collectorFactory = collectorFactory; + this.viewFactory = viewFactory; + this.notifier = notifier; + } + + @Override + public Filter<VmRef> getFilter() { + return filter; + } + + private AppCache getCache(VmRef ref) { + ApplicationCache applicationCache = service.getApplicationCache(); + AppCache cache = (AppCache) applicationCache.getAttribute(ref.getVmId()); + if (cache == null) { + AppCacheKey mainKey = new AppCacheKey(ref.getVmId(), ThreadInformationController.class); + cache = new AppCache(mainKey, applicationCache); + applicationCache.addAttribute(ref.getVmId(), cache); + } + return cache; + } + + @Override + public InformationServiceController<VmRef> getInformationServiceController(VmRef ref) { + AppCache cache = getCache(ref); + AppCacheKey key = new AppCacheKey(ref.getVmId(), ThreadInformationController.class); + ThreadInformationController controller = cache.retrieve(key); + if (controller == null) { + controller = new ThreadInformationController(ref, service, + vmInfoDao, + lockInfoDao, + collectorFactory, + viewFactory, + notifier); + cache.save(key, controller); + } + return controller; + } + + @Override + public int getOrderValue() { + return ORDER; + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/internal/ThreadTableController.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,218 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal; + +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.storage.core.experimental.statement.ResultHandler; +import com.redhat.thermostat.thread.client.common.ThreadTableBean; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.client.common.model.timeline.ThreadInfo; +import com.redhat.thermostat.thread.client.common.view.ThreadTableView; +import com.redhat.thermostat.thread.model.SessionID; +import com.redhat.thermostat.thread.model.ThreadState; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class ThreadTableController extends CommonController { + + private ThreadTableView threadTableView; + private ThreadCollector collector; + + private volatile boolean stopLooping; + + public ThreadTableController(ThreadTableView threadTableView, + ThreadCollector collector, + Timer timer) + { + super(timer, threadTableView); + this.threadTableView = threadTableView; + this.collector = collector; + timer.setAction(new ThreadTableControllerAction()); + } + + @Override + protected void onViewVisible() { + stopLooping = false; + } + + @Override + protected void onViewHidden() { + stopLooping = true; + } + + private class ThreadTableControllerAction implements Runnable { + + private ThreadResultHandler handler; + private Range<Long> range; + private SessionID lastSession; + private long lastUpdate; + + public ThreadTableControllerAction() { + handler = new ThreadResultHandler(); + resetState(); + } + + private void resetState() { + handler.threadStates.clear(); + threadTableView.clear(); + range = null; + lastUpdate = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1); + } + + @Override + public void run() { + SessionID session = ThreadTableController.this.session; + if (session == null) { + // no session selected, but let's try to default to the last + // available + session = collector.getLastThreadSession(); + if (session == null) { + // ok, really no data, let's skip this round + return; + } + } + + if (lastSession == null || + !session.get().equals(lastSession.get())) { + // since we only visualise one session at a time and this is + // a new session, let's clear the view + resetState(); + } + lastSession = session; + + // get the full range of known timelines per vm + Range<Long> totalRange = collector.getThreadRange(session); + if (totalRange == null) { + // this just means we don't have any data yet + return; + } + + range = new Range<>(lastUpdate, totalRange.getMax()); + lastUpdate = totalRange.getMax(); + + collector.getThreadStates(session, + handler, + range); + threadTableView.submitChanges(); + } + } + + private class ThreadResultHandler implements ResultHandler<ThreadState> { + private Map<ThreadInfo, ThreadTableBean> threadStates; + + public ThreadResultHandler() { + this.threadStates = new HashMap<>(); + } + + @Override + public boolean onResult(ThreadState thread) { + + ThreadInfo key = new ThreadInfo(); + key.setName(thread.getName()); + key.setId(thread.getId()); + + ThreadTableBean bean = threadStates.get(key); + if (bean == null) { + bean = new ThreadTableBean(); + bean.setName(thread.getName()); + bean.setId(thread.getId()); + bean.setStartTimeStamp(thread.getTimeStamp()); + threadStates.put(key, bean); + } + + setCurrentStateTime(bean, thread); + + double totalRunningTime = bean.getRunningTime() + + bean.getMonitorTime() + + bean.getSleepingTime() + + bean.getWaitingTime(); + if (totalRunningTime > 0) { + double percent = (bean.getRunningTime() / totalRunningTime) * 100; + bean.setRunningPercent(percent); + + percent = (bean.getWaitingTime() / totalRunningTime) * 100; + bean.setWaitingPercent(percent); + + percent = (bean.getMonitorTime() / totalRunningTime) * 100; + bean.setMonitorPercent(percent); + + percent = (bean.getSleepingTime() / totalRunningTime) * 100; + bean.setSleepingPercent(percent); + } + + bean.setBlockedCount(thread.getBlockedCount()); + bean.setWaitedCount(thread.getWaitedCount()); + + bean.setStopTimeStamp(thread.getTimeStamp()); + + threadTableView.display(bean); + + boolean _stopLooping = stopLooping; + return !_stopLooping; + } + } + + void setCurrentStateTime(ThreadTableBean bean, ThreadState thread) { + Thread.State threadState = Thread.State.valueOf(thread.getState()); + + switch (threadState) { + case RUNNABLE: + bean.setRunningTime(bean.getRunningTime() + 1); + break; + + case BLOCKED: + bean.setMonitorTime(bean.getMonitorTime() + 1); + break; + + case TIMED_WAITING: + bean.setSleepingTime(bean.getSleepingTime() + 1); + break; + + case WAITING: + bean.setWaitingTime(bean.getWaitingTime() + 1); + break; + + case NEW: + case TERMINATED: + default: + break; + } + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/internal/ThreadTimelineController.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,178 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal; + +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.storage.core.experimental.statement.ResultHandler; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.client.common.model.timeline.ThreadInfo; +import com.redhat.thermostat.thread.client.common.model.timeline.TimelineFactory; +import com.redhat.thermostat.thread.client.common.model.timeline.TimelineProbe; +import com.redhat.thermostat.thread.client.common.view.ThreadTimelineView; +import com.redhat.thermostat.thread.model.SessionID; +import com.redhat.thermostat.thread.model.ThreadState; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +public class ThreadTimelineController extends CommonController { + + private static final boolean _DEBUG_BLOCK_TIMING_ = false; + + private ThreadTimelineView view; + private ThreadCollector collector; + + private volatile boolean stopLooping; + + public ThreadTimelineController(ThreadTimelineView view, + ThreadCollector collector, + Timer timer) + { + super(timer, view); + this.view = view; + this.collector = collector; + + timer.setAction(new ThreadTimelineControllerAction()); + } + + private class ThreadTimelineControllerAction implements Runnable { + + private Range<Long> range; + private Range<Long> lastRange; + private ThreadStateResultHandler threadStateResultHandler; + private long lastUpdate; + + private SessionID lastSession; + + public ThreadTimelineControllerAction() { + lastUpdate = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1); + threadStateResultHandler = new ThreadStateResultHandler(); + } + + private void resetState() { + view.clear(); + lastRange = null; + lastUpdate = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1); + threadStateResultHandler.knownStates.clear(); + threadStateResultHandler.key = new ThreadInfo(); + } + + @Override + public void run() { + SessionID session = ThreadTimelineController.this.session; + if (session == null) { + // no session selected, but let's try to default to the last + // available + session = collector.getLastThreadSession(); + if (session == null) { + // ok, really no data, let's skip this round + return; + } + } + + if (lastSession == null || + !session.get().equals(lastSession.get())) + { + // since we only visualise one session at a time and this is + // a new session, let's clear the view + resetState(); + } + lastSession = session; + + // get the full range of known timelines per vm + Range<Long> totalRange = collector.getThreadRange(session); + if (totalRange == null) { + // this just means we don't have any data yet + return; + } + + if (!totalRange.equals(lastRange)) { + view.setTotalRange(totalRange); + } + lastRange = totalRange; + + range = new Range<>(lastUpdate, totalRange.getMax()); + lastUpdate = totalRange.getMax(); + + collector.getThreadStates(session, + threadStateResultHandler, + range); + } + } + + @Override + protected void onViewVisible() { + stopLooping = false; + } + + @Override + protected void onViewHidden() { + stopLooping = true; + } + + private class ThreadStateResultHandler implements ResultHandler<ThreadState> { + private ThreadInfo key; + private Set<ThreadInfo> knownStates; + + public ThreadStateResultHandler() { + this.key = new ThreadInfo(); + knownStates = new HashSet<>(); + } + + @Override + public boolean onResult(ThreadState state) { + + key.setName(state.getName()); + key.setId(state.getId()); + + ThreadInfo info = new ThreadInfo(key); + if (!knownStates.contains(key)) { + view.addThread(info); + knownStates.add(info); + } + + TimelineProbe probe = TimelineFactory.createTimelineProbe(state); + view.addProbe(info, probe); + + boolean _stopLooping = stopLooping; + return !_stopLooping; + } + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/internal/VmDeadLockController.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,204 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.util.Objects; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.client.core.progress.ProgressHandle; +import com.redhat.thermostat.client.core.progress.ProgressNotifier; +import com.redhat.thermostat.client.core.views.BasicView.Action; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.Timer.SchedulingType; +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.shared.locale.LocalizedString; +import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.dao.VmInfoDAO; +import com.redhat.thermostat.thread.client.common.DeadlockParser; +import com.redhat.thermostat.thread.client.common.DeadlockParser.Information; +import com.redhat.thermostat.thread.client.common.DeadlockParser.ParseException; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.client.common.view.VmDeadLockView; +import com.redhat.thermostat.thread.client.common.view.VmDeadLockView.VmDeadLockViewAction; +import com.redhat.thermostat.thread.model.VmDeadLockData; + +public class VmDeadLockController { + + private static final Logger logger = LoggingUtils.getLogger(VmDeadLockController.class); + private static final Translate<LocaleResources> translate = LocaleResources.createLocalizer(); + + private static final String NO_DEADLOCK = translate.localize(LocaleResources.NO_DEADLOCK_DETECTED).getContents(); + + private VmInfoDAO vmInfoDAO; + private VmRef vmRef; + + private VmDeadLockView view; + private ThreadCollector collector; + private Timer timer; + private ExecutorService executor; + private ProgressNotifier notifier; + + private final AtomicReference<String> descriptionRef = new AtomicReference<>(""); + private String previousDeadlockData = null; + + + public VmDeadLockController(VmInfoDAO vmInfoDAO, VmRef vmRef, VmDeadLockView view, ThreadCollector collector, Timer timer, + ExecutorService executor, ProgressNotifier notifier) { + this.vmInfoDAO = vmInfoDAO; + this.vmRef = vmRef; + this.view = view; + this.collector = collector; + this.timer = timer; + this.executor = executor; + this.notifier = Objects.requireNonNull(notifier); + } + + public void initialize() { + view.addVmDeadLockViewActionListener(new ActionListener<VmDeadLockViewAction>() { + @Override + public void actionPerformed(ActionEvent<VmDeadLockViewAction> actionEvent) { + switch (actionEvent.getActionId()) { + case CHECK_FOR_DEADLOCK: + executor.execute(new Runnable() { + @Override + public void run() { + LocalizedString message = translate.localize(LocaleResources.CHECKING_FOR_DEADLOCKS); + ProgressHandle handle = new ProgressHandle(message); + handle.setIndeterminate(true); + + notifier.register(handle); + + handle.runTask(new Runnable() { + @Override + public void run() { + checkForDeadLock(); + updateViewIfNeeded(); + } + }); + } + }); + break; + default: + break; + } + } + }); + + timer.setAction(new Runnable() { + @Override + public void run() { + checkStorageForDeadLockData(); + updateViewIfNeeded(); + } + }); + timer.setDelay(5); + timer.setInitialDelay(0); + timer.setTimeUnit(TimeUnit.SECONDS); + timer.setSchedulingType(SchedulingType.FIXED_DELAY); + + view.addActionListener(new ActionListener<Action>() { + @Override + public void actionPerformed(ActionEvent<Action> actionEvent) { + switch (actionEvent.getActionId()) { + case HIDDEN: + timer.stop(); + break; + case VISIBLE: + timer.start(); + break; + } + } + }); + + view.setCheckDeadlockControlEnabled(vmInfoDAO.getVmInfo(vmRef).isAlive()); + } + + private void checkForDeadLock() { + askAgentToCheckForDeadLock(); + checkStorageForDeadLockData(); + } + + private void askAgentToCheckForDeadLock() { + collector.requestDeadLockCheck(); + } + + private void checkStorageForDeadLockData() { + VmDeadLockData data = collector.getLatestDeadLockData(); + if (data == null) { + // no deadlock data; so don't update anything + return; + } + + String description = data.getDeadLockDescription(); + if (description.equals(VmDeadLockData.NO_DEADLOCK)) { + description = NO_DEADLOCK; + } + this.descriptionRef.set(description); + + } + + private void updateViewIfNeeded() { + String rawDeadlockData = descriptionRef.get(); + + if (!rawDeadlockData.equals(previousDeadlockData)) { + Information parsed = null; + + if (!rawDeadlockData.equals(NO_DEADLOCK)) { + try { + parsed = new DeadlockParser().parse(new BufferedReader(new StringReader(rawDeadlockData))); + } catch (IOException | ParseException e) { + logger.log(Level.FINE, "Failed to parse deadlock data. Visualizations might not show up correctly.", e); + } + } + + view.setDeadLockInformation(parsed, rawDeadlockData); + previousDeadlockData = rawDeadlockData; + } + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/internal/cache/AppCache.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,86 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal.cache; + +import com.redhat.thermostat.common.ApplicationCache; +import java.util.HashMap; + +/** + * + */ +public class AppCache { + private static final String LOCK = new String("AppCacheLock"); + + private AppCacheKey root; + private ApplicationCache cache; + + public AppCache(AppCacheKey root, ApplicationCache cache) { + this.root = root; + this.cache = cache; + } + + public <E> void save(AppCacheKey key, E value) { + synchronized (LOCK) { + HashMap<AppCacheKey, E> localCache = getLocalCache(); + localCache.put(key, value); + saveLocalCache(localCache); + } + } + + public <E> E retrieve(AppCacheKey key) { + synchronized (LOCK) { + HashMap<AppCacheKey, E> localCache = getLocalCache(); + return localCache.get(key); + } + } + + private <E> HashMap<AppCacheKey, E> getLocalCache() { + HashMap<AppCacheKey, E> localCache = + (HashMap<AppCacheKey, E>) cache.getAttribute(root); + + if (localCache == null) { + localCache = new HashMap<>(); + saveLocalCache(localCache); + } + + return localCache; + } + + private <E> void saveLocalCache(HashMap<AppCacheKey, E> localCache) { + cache.addAttribute(root, localCache); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/internal/cache/AppCacheKey.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,82 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal.cache; + +import java.util.Objects; + +/** + * + */ +public class AppCacheKey { + private String UUID; + private String targetClass; + + public AppCacheKey(Class<?> hostClass, Class<?> targetClass) { + this(hostClass.getSimpleName(), targetClass.getSimpleName()); + } + + public AppCacheKey(String UUID, Class<?> targetClass) { + this(UUID, targetClass.getSimpleName()); + } + + private AppCacheKey(String UUID, String targetClass) { + this.UUID = UUID; + this.targetClass = targetClass; + Objects.requireNonNull(UUID); + Objects.requireNonNull(targetClass); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + AppCacheKey that = (AppCacheKey) o; + + if (!UUID.equals(that.UUID)) return false; + if (!targetClass.equals(that.targetClass)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = UUID.hashCode(); + result = 31 * result + targetClass.hashCode(); + return result; + } +}
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/osgi/Activator.java Wed Apr 06 14:52:26 2016 +0200 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/osgi/Activator.java Fri Apr 08 13:18:48 2016 +0200 @@ -47,7 +47,7 @@ import com.redhat.thermostat.thread.client.common.ThreadViewProvider; import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory; import com.redhat.thermostat.thread.client.controller.ThreadInformationService; -import com.redhat.thermostat.thread.client.controller.impl.ThreadInformationServiceImpl; +import com.redhat.thermostat.thread.client.controller.internal.ThreadInformationServiceImpl; import com.redhat.thermostat.thread.dao.LockInfoDao; import java.util.Dictionary;
--- a/thread/client-controllers/src/main/resources/com/redhat/thermostat/thread/client/controller/impl/strings.properties Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -CONTROLLER_NAME = Threads -WARNING_CANNOT_ENABLE = Cannot enable Thread recording -WARNING_CANNOT_DISABLE = Cannot disable Thread recording -CHECKING_FOR_DEADLOCKS = Checking for deadlocks\u2026 -NO_DEADLOCK_DETECTED = No Deadlocks Detected. -STARTING_MONITORING = Starting thread monitoring\u2026 -STOPPING_MONITORING = Stopping thread monitoring\u2026 -LOADING_SESSION_LIST = Retrieving the list of recorded thread timeline sessions
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/main/resources/com/redhat/thermostat/thread/client/controller/internal/strings.properties Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,8 @@ +CONTROLLER_NAME = Threads +WARNING_CANNOT_ENABLE = Cannot enable Thread recording +WARNING_CANNOT_DISABLE = Cannot disable Thread recording +CHECKING_FOR_DEADLOCKS = Checking for deadlocks\u2026 +NO_DEADLOCK_DETECTED = No Deadlocks Detected. +STARTING_MONITORING = Starting thread monitoring\u2026 +STOPPING_MONITORING = Stopping thread monitoring\u2026 +LOADING_SESSION_LIST = Retrieving the list of recorded thread timeline sessions
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/LocaleResourcesTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl; - -import com.redhat.thermostat.testutils.AbstractLocaleResourcesTest; - -public class LocaleResourcesTest extends AbstractLocaleResourcesTest<LocaleResources> { - - @Override - protected Class<LocaleResources> getEnumClass() { - return LocaleResources.class; - } - - @Override - protected String getResourceBundle() { - return LocaleResources.RESOURCE_BUNDLE; - } - -} -
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/LockControllerTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl; - -import static org.mockito.Matchers.isA; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -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.client.core.views.BasicView; -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.Timer; -import com.redhat.thermostat.storage.core.VmRef; -import com.redhat.thermostat.thread.client.common.view.LockView; -import com.redhat.thermostat.thread.dao.LockInfoDao; -import com.redhat.thermostat.thread.model.LockInfo; - -public class LockControllerTest { - - private LockView view; - private Timer timer; - private LockInfoDao dao; - private VmRef vm; - - @Before - public void setup() { - view = mock(LockView.class); - timer = mock(Timer.class); - dao = mock(LockInfoDao.class); - vm = mock(VmRef.class); - } - - @Test - public void verifyVisibilityEnablesAndDisablesTimer() { - LockController controller = new LockController(view, timer, dao, vm); - controller.initialize(); - - ArgumentCaptor<ActionListener> actionListenerCaptor = ArgumentCaptor.forClass(ActionListener.class); - verify(view).addActionListener(actionListenerCaptor.capture()); - - ActionListener listener = actionListenerCaptor.getValue(); - listener.actionPerformed(new ActionEvent(view, BasicView.Action.VISIBLE)); - - verify(timer).start(); - - listener.actionPerformed(new ActionEvent(view, BasicView.Action.HIDDEN)); - - verify(timer).stop(); - } - - @Test - public void verifyViewIsNotUpdatedOnNoData() { - when(dao.getLatestLockInfo(vm)).thenReturn(null); - - LockController controller = new LockController(view, timer, dao, vm); - controller.initialize(); - - ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class); - verify(timer).setAction(captor.capture()); - Runnable updater = captor.getValue(); - - verify(view, never()).setLatestLockData(isA(LockInfo.class)); - - updater.run(); - - verify(view, never()).setLatestLockData(isA(LockInfo.class)); - } - - @Test - public void verifyViewIsUpdatedWithData() { - LockInfo lockInfo = new LockInfo(); - when(dao.getLatestLockInfo(vm)).thenReturn(lockInfo); - - LockController controller = new LockController(view, timer, dao, vm); - controller.initialize(); - - ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class); - verify(timer).setAction(captor.capture()); - Runnable updater = captor.getValue(); - - verify(view, never()).setLatestLockData(isA(LockInfo.class)); - - updater.run(); - - verify(view).setLatestLockData(lockInfo); - } -}
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadCountControllerTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,172 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl; - -import com.redhat.thermostat.client.core.views.BasicView; -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.Timer; -import com.redhat.thermostat.common.model.Range; -import com.redhat.thermostat.thread.client.common.chart.LivingDaemonThreadDifferenceChart; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; -import com.redhat.thermostat.thread.client.common.view.ThreadCountView; -import com.redhat.thermostat.thread.model.SessionID; -import com.redhat.thermostat.thread.model.ThreadSession; -import com.redhat.thermostat.thread.model.ThreadSummary; - -import java.awt.Color; -import java.util.ArrayList; -import java.util.List; - -import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner; - -import org.jfree.chart.JFreeChart; -import org.jfree.data.xy.XYDataset; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.mockito.Matchers.isA; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -// this is not a GUI test, but testGetThreadInformation uses AWT under the hood -@RunWith(CacioFESTRunner.class) -public class ThreadCountControllerTest { - - private Timer timer; - private Runnable threadAction; - private ThreadCountView view; - private ThreadCollector collector; - - private ActionListener<ThreadCountView.Action> actionListener; - - @Before - public void setUp() { - timer = mock(Timer.class); - view = mock(ThreadCountView.class); - collector = mock(ThreadCollector.class); - } - - @Test - public void testGetThreadInformation() { - - ArgumentCaptor<LivingDaemonThreadDifferenceChart> modelCaptor = - ArgumentCaptor.forClass(LivingDaemonThreadDifferenceChart.class); - - - ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class); - doNothing().when(timer).setAction(captor.capture()); - - ThreadCountController controller = new ThreadCountController(view, collector, timer); - controller.initialize(); - - ThreadSummary summary = mock(ThreadSummary.class); - when(summary.getTimeStamp()).thenReturn(5l); - when(summary.getCurrentLiveThreads()).thenReturn(42l); - when(summary.getCurrentDaemonThreads()).thenReturn(2l); - - ThreadSummary summary0 = mock(ThreadSummary.class); - when(summary0.getTimeStamp()).thenReturn(2l); - when(summary0.getCurrentLiveThreads()).thenReturn(43l); - when(summary0.getCurrentDaemonThreads()).thenReturn(1l); - - List<ThreadSummary> summaries = new ArrayList<>(); - summaries.add(summary); - summaries.add(summary0); - - SessionID lastSession = mock(SessionID.class); - when(collector.getLastThreadSession()).thenReturn(lastSession); - - when(collector.getLatestThreadSummary()).thenReturn(summary); - - List<ThreadSession> sessions = new ArrayList<>(); - when(collector.getThreadSessions(isA(Range.class))).thenReturn(sessions); - when(collector.getThreadSummary(isA(Range.class))).thenReturn(summaries); - - threadAction = captor.getValue(); - threadAction.run(); - - verify(collector).getLatestThreadSummary(); - - verify(view).setLiveThreads("42"); - verify(view).setDaemonThreads("2"); - - verify(view).updateLivingDaemonTimeline(modelCaptor.capture()); - LivingDaemonThreadDifferenceChart model = modelCaptor.getValue(); - - assertNotNull(model); - - JFreeChart chart = model.createChart(100, Color.BLACK); - XYDataset dataSet = chart.getXYPlot().getDataset(); - assertEquals(2, dataSet.getSeriesCount()); - - // total and living - assertEquals(2l, dataSet.getX(0, 0)); - assertEquals(5l, dataSet.getX(0, 1)); - - // the actual numbers - assertEquals(43.0, dataSet.getY(0, 0)); - assertEquals(42.0, dataSet.getY(0, 1)); - assertEquals(1.0, dataSet.getY(1, 0)); - assertEquals(2.0, dataSet.getY(1, 1)); - } - - @Test - public void testTimerStartAndStop() { - ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class); - doNothing().when(view).addActionListener(viewArgumentCaptor.capture()); - - ThreadCountController controller = new ThreadCountController(view, collector, timer); - controller.initialize(); - - actionListener = viewArgumentCaptor.getValue(); - actionListener.actionPerformed(new ActionEvent<>(view, BasicView.Action.VISIBLE)); - - verify(timer).start(); - - actionListener.actionPerformed(new ActionEvent<>(view, BasicView.Action.HIDDEN)); - - verify(timer).stop(); - } -} -
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationControllerTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,350 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl; - -import com.redhat.thermostat.client.core.progress.ProgressNotifier; -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.ApplicationCache; -import com.redhat.thermostat.common.ApplicationService; -import com.redhat.thermostat.common.Timer; -import com.redhat.thermostat.common.TimerFactory; -import com.redhat.thermostat.common.model.Range; -import com.redhat.thermostat.storage.core.HostRef; -import com.redhat.thermostat.storage.core.VmRef; -import com.redhat.thermostat.storage.dao.VmInfoDAO; -import com.redhat.thermostat.storage.model.VmInfo; -import com.redhat.thermostat.thread.client.common.ThreadTableBean; -import com.redhat.thermostat.thread.client.common.ThreadViewProvider; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory; -import com.redhat.thermostat.thread.client.common.view.LockView; -import com.redhat.thermostat.thread.client.common.view.ThreadCountView; -import com.redhat.thermostat.thread.client.common.view.ThreadTableView; -import com.redhat.thermostat.thread.client.common.view.ThreadTableView.ThreadSelectionAction; -import com.redhat.thermostat.thread.client.common.view.ThreadTimelineView; -import com.redhat.thermostat.thread.client.common.view.ThreadView; -import com.redhat.thermostat.thread.client.common.view.VmDeadLockView; -import com.redhat.thermostat.thread.dao.LockInfoDao; -import com.redhat.thermostat.thread.model.SessionID; -import com.redhat.thermostat.thread.model.ThreadSession; -import junit.framework.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutorService; - -import static org.mockito.Matchers.isA; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class ThreadInformationControllerTest { - - private ThreadView view; - - private ActionListener<ThreadTableView.ThreadSelectionAction> threadTableActionListener; - - private ThreadViewProvider viewFactory; - private ThreadInformationController controller; - - private ApplicationService appService; - private ExecutorService appExecutor; - - private VmInfo vmInfo; - private VmInfoDAO vmInfoDao; - private LockInfoDao lockInfoDao; - - private ThreadTableView threadTableView; - private VmDeadLockView deadLockView; - private ThreadTimelineView threadTimelineView; - private ThreadCountView threadCountView; - private LockView lockView; - - @Before - public void setUp() { - - appService = mock(ApplicationService.class); - vmInfo = mock(VmInfo.class); - when(vmInfo.isAlive()).thenReturn(true); - vmInfoDao = mock(VmInfoDAO.class); - when(vmInfoDao.getVmInfo(isA(VmRef.class))).thenReturn(vmInfo); - lockInfoDao = mock(LockInfoDao.class); - setUpTimers(); - setupCache(); - setupExecutor(); - setUpView(); - } - - private void setUpView() { - deadLockView = mock(VmDeadLockView.class); - threadTableView = mock(ThreadTableView.class); - threadTimelineView = mock(ThreadTimelineView.class); - threadCountView = mock(ThreadCountView.class); - lockView = mock(LockView.class); - - view = mock(ThreadView.class); - viewFactory = mock(ThreadViewProvider.class); - when(viewFactory.createView()).thenReturn(view); - - when(view.createDeadLockView()).thenReturn(deadLockView); - when(view.createThreadTableView()).thenReturn(threadTableView); - when(view.createThreadTimelineView()).thenReturn(threadTimelineView); - when(view.createThreadCountView()).thenReturn(threadCountView); - when(view.createLockView()).thenReturn(lockView); - - } - - private void setUpTimers() { - Timer timer = mock(Timer.class); - - TimerFactory timerFactory = mock(TimerFactory.class); - when(timerFactory.createTimer()).thenReturn(timer); - when(appService.getTimerFactory()).thenReturn(timerFactory); - } - - private void setupCache() { - ApplicationCache cache = mock(ApplicationCache.class); - when(appService.getApplicationCache()).thenReturn(cache); - } - - private void setupExecutor() { - appExecutor = mock(ExecutorService.class); - when(appService.getApplicationExecutor()).thenReturn(appExecutor); - } - - private void setUpListeners() { - doNothing().when(view).addActionListener(any(ActionListener.class)); - - ArgumentCaptor<ActionListener> threadTableViewCaptor = ArgumentCaptor.forClass(ActionListener.class); - doNothing().when(threadTableView).addThreadSelectionActionListener(threadTableViewCaptor.capture()); - - createController(); - - threadTableActionListener = threadTableViewCaptor.getValue(); - } - - private void createController() { - - VmRef ref = mock(VmRef.class); - HostRef agent = mock(HostRef.class); - when(ref.getHostRef()).thenReturn(agent); - when(agent.getAgentId()).thenReturn("0xcafe"); - - ThreadCollectorFactory collectorFactory = mock(ThreadCollectorFactory.class); - ThreadCollector collector = mock(ThreadCollector.class); - when(collectorFactory.getCollector(ref)).thenReturn(collector); - - ProgressNotifier notifier = mock(ProgressNotifier.class); - - controller = new ThreadInformationController(ref, appService, vmInfoDao, lockInfoDao, - collectorFactory, - viewFactory, notifier); - } - - @Test - public void verifyViewCreateSubViewCalled() { - - createController(); - - verify(view).createThreadTableView(); - verify(view).createDeadLockView(); - verify(view).createThreadTimelineView(); - verify(view).createThreadCountView(); - } - - @Test - public void verifyLiveRecording() { - - ActionListener<ThreadView.ThreadAction> threadActionListener; - ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class); - doNothing().when(view).addThreadActionListener(viewArgumentCaptor.capture()); - - VmRef ref = mock(VmRef.class); - when(ref.getVmId()).thenReturn("42"); - HostRef agent = mock(HostRef.class); - when(ref.getHostRef()).thenReturn(agent); - when(agent.getAgentId()).thenReturn("0xcafe"); - - ThreadCollector collector = mock(ThreadCollector.class); - when(collector.isHarvesterCollecting()).thenReturn(false).thenReturn(true); - when(collector.startHarvester()).thenReturn(true); - when(collector.stopHarvester()).thenReturn(true).thenReturn(false); - - ThreadCollectorFactory collectorFactory = mock(ThreadCollectorFactory.class); - when(collectorFactory.getCollector(ref)).thenReturn(collector); - - ProgressNotifier notifier = mock(ProgressNotifier.class); - - ArgumentCaptor<Runnable> longRunningTaskCaptor = ArgumentCaptor.forClass(Runnable.class); - doNothing().when(appExecutor).execute(longRunningTaskCaptor.capture()); - - controller = new ThreadInformationController(ref, appService, - vmInfoDao, lockInfoDao, - collectorFactory, - viewFactory, notifier); - - verify(collector).isHarvesterCollecting(); - verify(view, times(1)).setRecording(ThreadView.MonitoringState.STOPPED, false); - - // each action event posts a task to the executor. - // make sure the task is posted and execute it manually in tests to see its effects. - - threadActionListener = viewArgumentCaptor.getValue(); - threadActionListener.actionPerformed(new ActionEvent<>(view, ThreadView.ThreadAction.START_LIVE_RECORDING)); - - verify(appExecutor, times(1)).execute(isA(Runnable.class)); - longRunningTaskCaptor.getValue().run(); - - verify(view, times(1)).setRecording(ThreadView.MonitoringState.STARTING, false); - verify(view, times(1)).setRecording(ThreadView.MonitoringState.STARTED, false); - verify(collector).startHarvester(); - - threadActionListener.actionPerformed(new ActionEvent<>(view, ThreadView.ThreadAction.STOP_LIVE_RECORDING)); - - verify(appExecutor, times(2)).execute(isA(Runnable.class)); - longRunningTaskCaptor.getValue().run(); - - verify(collector).stopHarvester(); - verify(view, times(1)).setRecording(ThreadView.MonitoringState.STOPPING, false); - verify(view, times(2)).setRecording(ThreadView.MonitoringState.STOPPED, false); - - threadActionListener.actionPerformed(new ActionEvent<>(view, ThreadView.ThreadAction.STOP_LIVE_RECORDING)); - - verify(appExecutor, times(3)).execute(isA(Runnable.class)); - longRunningTaskCaptor.getValue().run(); - - verify(collector, times(2)).stopHarvester(); - verify(view, times(2)).setRecording(ThreadView.MonitoringState.STOPPING, false); - verify(view, times(3)).setRecording(ThreadView.MonitoringState.STOPPED, false); - } - - @Test - public void verifyRecordingControlDisabledForDeadVms() { - when(vmInfo.isAlive()).thenReturn(false); - - createController(); - - verify(view).setEnableRecordingControl(false); - } - - @Test - public void verifyTableViewLinksToDetailsView() { - setUpListeners(); - - ThreadTableBean bean = mock(ThreadTableBean.class); - - ActionEvent<ThreadSelectionAction> event = - new ActionEvent<>(threadTableView, ThreadSelectionAction.SHOW_THREAD_DETAILS); - event.setPayload(bean); - - threadTableActionListener.actionPerformed(event); - verify(view).displayThreadDetails(bean); - } - - @Test - public void verifySessionListDisplays() { - - ThreadCollector collector = mock(ThreadCollector.class); - List<ThreadSession> list = new ArrayList<>(); - list.add(mock(ThreadSession.class)); - list.add(mock(ThreadSession.class)); - - when(collector.getThreadSessions(any(Range.class))).thenReturn(list); - - ActionListener<ThreadView.ThreadAction> threadActionListener; - ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class); - doNothing().when(view).addThreadActionListener(viewArgumentCaptor.capture()); - - ArgumentCaptor<Runnable> taskCaptor = ArgumentCaptor.forClass(Runnable.class); - doNothing().when(appExecutor).execute(taskCaptor.capture()); - - createController(); - - controller.___injectCollectorForTesting(collector); - - threadActionListener = viewArgumentCaptor.getValue(); - ActionEvent<ThreadView.ThreadAction> action = new ActionEvent<>(view, ThreadView.ThreadAction.REQUEST_DISPLAY_RECORDED_SESSIONS); - threadActionListener.actionPerformed(action); - - Runnable runnable = taskCaptor.getValue(); - runnable.run(); - - ArgumentCaptor<List> listCaptor = ArgumentCaptor.forClass(List.class); - verify(view).displayTimelineSessionList(listCaptor.capture()); - - Assert.assertTrue(listCaptor.getValue().equals(list)); - } - - @Test - public void verifySessionLoads() { - - ThreadTimelineController timeline = mock(ThreadTimelineController.class); - ThreadTableController table = mock(ThreadTableController.class); - ThreadCountController count = mock(ThreadCountController.class); - LockController lock = mock(LockController.class); - VmDeadLockController deadLock = mock(VmDeadLockController.class); - - ThreadSession session = mock(ThreadSession.class); - SessionID id = mock(SessionID.class); - when(session.getSessionID()).thenReturn(id); - - ActionListener<ThreadView.ThreadAction> threadActionListener; - ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class); - doNothing().when(view).addThreadActionListener(viewArgumentCaptor.capture()); - - createController(); - - controller.___injectControllersForTesting(timeline, table, count, lock, deadLock); - - threadActionListener = viewArgumentCaptor.getValue(); - ActionEvent<ThreadView.ThreadAction> action = new ActionEvent<>(view, ThreadView.ThreadAction.REQUEST_LOAD_SESSION); - action.setPayload(session); - - threadActionListener.actionPerformed(action); - - verify(timeline).setSession(id); - verify(table).setSession(id); - } -} -
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTableControllerTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl; - -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.Timer; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; -import com.redhat.thermostat.thread.client.common.view.ThreadTableView; - -public class ThreadTableControllerTest { - - private ThreadTableView view; - private ThreadCollector collector; - - private Timer timer; - - private ActionListener<ThreadTableView.Action> actionListener; - ArgumentCaptor<Runnable> timerActionCaptor; - - @Before - public void setUp() { - collector = mock(ThreadCollector.class); - - timer = mock(Timer.class); - - view = mock(ThreadTableView.class); - - setUpTimers(); - } - - private void setUpTimers() { - timer = mock(Timer.class); - timerActionCaptor = ArgumentCaptor.forClass(Runnable.class); - doNothing().when(timer).setAction(timerActionCaptor.capture()); - } - - @Test - public void testStartThreadTableController() { - - ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class); - doNothing().when(view).addActionListener(viewArgumentCaptor.capture()); - - ThreadTableController controller = new ThreadTableController(view, collector, timer); - controller.initialize(); - - actionListener = viewArgumentCaptor.getValue(); - actionListener.actionPerformed(new ActionEvent<>(view, ThreadTableView.Action.VISIBLE)); - - verify(timer).start(); - - actionListener.actionPerformed(new ActionEvent<>(view, ThreadTableView.Action.HIDDEN)); - - verify(timer).stop(); - } -} -
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTimelineControllerTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,189 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl; - -import com.redhat.thermostat.common.Timer; -import com.redhat.thermostat.common.model.Range; -import com.redhat.thermostat.storage.core.experimental.statement.ResultHandler; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; -import com.redhat.thermostat.thread.client.common.model.timeline.ThreadInfo; -import com.redhat.thermostat.thread.client.common.view.ThreadTimelineView; -import com.redhat.thermostat.thread.model.SessionID; -import com.redhat.thermostat.thread.model.ThreadState; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class ThreadTimelineControllerTest { - - private ThreadTimelineView view; - private ThreadCollector collector; - private Timer timer; - private SessionID session; - - @Before - public void setup() { - view = mock(ThreadTimelineView.class); - collector = mock(ThreadCollector.class); - timer = mock(Timer.class); - session = mock(SessionID.class); - when(session.get()).thenReturn("42"); - when(collector.getLastThreadSession()).thenReturn(session); - } - - @Test - public void verifySession() { - ArgumentCaptor<Runnable> captor = - ArgumentCaptor.forClass(Runnable.class); - doNothing().when(timer).setAction(captor.capture()); - - ThreadTimelineController controller = - new ThreadTimelineController(view, collector, timer); - Runnable timerAction = captor.getValue(); - - timerAction.run(); - - verify(collector).getLastThreadSession(); - verify(collector).getThreadRange(session); - } - - @Test - public void verifySessionIfSet() { - ArgumentCaptor<Runnable> captor = - ArgumentCaptor.forClass(Runnable.class); - doNothing().when(timer).setAction(captor.capture()); - - SessionID newSession = mock(SessionID.class); - when(newSession.get()).thenReturn("0"); - - ThreadTimelineController controller = - new ThreadTimelineController(view, collector, timer); - Runnable timerAction = captor.getValue(); - - timerAction.run(); - - verify(collector).getThreadRange(session); - - controller.setSession(newSession); - - timerAction.run(); - - verify(collector).getThreadRange(newSession); - } - - @Test - public void verifyRange() { - ArgumentCaptor<Runnable> captor = - ArgumentCaptor.forClass(Runnable.class); - doNothing().when(timer).setAction(captor.capture()); - - Range<Long> range = new Range<>(0l, 10l); - when(collector.getThreadRange(session)).thenReturn(range); - - ThreadTimelineController controller = - new ThreadTimelineController(view, collector, timer); - Runnable timerAction = captor.getValue(); - - timerAction.run(); - - verify(collector).getThreadRange(session); - verify(view).setTotalRange(range); - } - - @Test - public void testAllBeansAreLoaded() { - ArgumentCaptor<Runnable> captor = - ArgumentCaptor.forClass(Runnable.class); - doNothing().when(timer).setAction(captor.capture()); - - ArgumentCaptor<ResultHandler> captor2 = - ArgumentCaptor.forClass(ResultHandler.class); - doNothing().when(collector).getThreadStates(any(SessionID.class), - captor2.capture(), - any(Range.class)); - - Range<Long> range = new Range<>(0l, 10l); - when(collector.getThreadRange(session)).thenReturn(range); - - ThreadTimelineController controller = - new ThreadTimelineController(view, collector, timer); - Runnable timerAction = captor.getValue(); - - timerAction.run(); - - ResultHandler handler = captor2.getValue(); - - ThreadState state0 = mock(ThreadState.class); - when(state0.getName()).thenReturn("state0"); - when(state0.getId()).thenReturn(0l); - when(state0.getState()).thenReturn("NEW"); - - ThreadState state1 = mock(ThreadState.class); - when(state1.getName()).thenReturn("state1"); - when(state1.getId()).thenReturn(1l); - when(state1.getState()).thenReturn("NEW"); - - ThreadState state2 = mock(ThreadState.class); - when(state2.getName()).thenReturn("state2"); - when(state2.getId()).thenReturn(2l); - when(state2.getState()).thenReturn("NEW"); - - handler.onResult(state0); - handler.onResult(state1); - handler.onResult(state2); - - ThreadInfo info = new ThreadInfo(); - info.setName("state0"); - info.setId(0l); - - verify(view).addThread(info); - - info.setName("state1"); - info.setId(1l); - verify(view).addThread(info); - - info.setName("state2"); - info.setId(2l); - verify(view).addThread(info); - } -}
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/VmDeadLockControllerTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,245 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl; - -import static org.mockito.Matchers.isA; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.TimeUnit; - -import com.redhat.thermostat.storage.core.VmRef; -import com.redhat.thermostat.storage.dao.VmInfoDAO; -import com.redhat.thermostat.storage.model.VmInfo; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.redhat.thermostat.client.core.progress.ProgressNotifier; -import com.redhat.thermostat.client.core.views.BasicView; -import com.redhat.thermostat.client.core.views.BasicView.Action; -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.Timer; -import com.redhat.thermostat.common.Timer.SchedulingType; -import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; -import com.redhat.thermostat.thread.client.common.view.VmDeadLockView; -import com.redhat.thermostat.thread.client.common.view.VmDeadLockView.VmDeadLockViewAction; -import com.redhat.thermostat.thread.model.VmDeadLockData; - -public class VmDeadLockControllerTest { - - private VmInfoDAO vmInfoDao; - private VmInfo vmInfo; - private VmRef vmRef; - private Timer timer; - private VmDeadLockView view; - private ThreadCollector collector; - private ExecutorService executor; - private ProgressNotifier notifier; - - private VmDeadLockController controller; - - @Before - public void setUp() { - vmInfoDao = mock(VmInfoDAO.class); - - vmInfo = mock(VmInfo.class); - when(vmInfoDao.getVmInfo(isA(VmRef.class))).thenReturn(vmInfo); - when(vmInfo.isAlive()).thenReturn(true); - - vmRef = mock(VmRef.class); - - timer = mock(Timer.class); - - view = mock(VmDeadLockView.class); - - collector = mock(ThreadCollector.class); - - executor = mock(ExecutorService.class); - - notifier = mock(ProgressNotifier.class); - - controller = new VmDeadLockController(vmInfoDao, vmRef, view, collector, timer, executor, notifier); - } - - @Test - public void verifyInitilizeRegistersActionListener() { - controller.initialize(); - - verify(view).addVmDeadLockViewActionListener(isA(ActionListener.class)); - } - - @Test - public void verifyRealDeadLockDataIsDisplayedOnViewAction() { - final String DESCRIPTION = "foo bar"; - VmDeadLockData data = new VmDeadLockData("foo-agent"); - data.setDeadLockDescription(DESCRIPTION); - - ArgumentCaptor<Runnable> executionCaptor = ArgumentCaptor.forClass(Runnable.class); - doNothing().when(executor).execute(executionCaptor.capture()); - - controller.initialize(); - - ArgumentCaptor<ActionListener> listenerCaptor = (ArgumentCaptor<ActionListener>) ArgumentCaptor.forClass(ActionListener.class); - verify(view).addVmDeadLockViewActionListener(listenerCaptor.capture()); - - ActionListener<VmDeadLockViewAction> listener = (ActionListener<VmDeadLockViewAction>) listenerCaptor.getValue(); - - when(collector.getLatestDeadLockData()).thenReturn(data); - - listener.actionPerformed(new ActionEvent<VmDeadLockViewAction>(view, VmDeadLockViewAction.CHECK_FOR_DEADLOCK)); - - Runnable deferredTask = executionCaptor.getValue(); - deferredTask.run(); - - verify(collector).requestDeadLockCheck(); - verify(view).setDeadLockInformation(null, DESCRIPTION); - } - - @Test - public void verifyNoDeadLockDataIsDisplayedOnViewAction() { - VmDeadLockData data = new VmDeadLockData("foo-agent"); - data.setDeadLockDescription(VmDeadLockData.NO_DEADLOCK); - - ArgumentCaptor<Runnable> executionCaptor = ArgumentCaptor.forClass(Runnable.class); - doNothing().when(executor).execute(executionCaptor.capture()); - - controller.initialize(); - - ArgumentCaptor<ActionListener> listenerCaptor = (ArgumentCaptor<ActionListener>) ArgumentCaptor.forClass(ActionListener.class); - verify(view).addVmDeadLockViewActionListener(listenerCaptor.capture()); - - ActionListener<VmDeadLockViewAction> listener = (ActionListener<VmDeadLockViewAction>) listenerCaptor.getValue(); - - when(collector.getLatestDeadLockData()).thenReturn(data); - - listener.actionPerformed(new ActionEvent<VmDeadLockViewAction>(view, VmDeadLockViewAction.CHECK_FOR_DEADLOCK)); - - Runnable deferredTask = executionCaptor.getValue(); - deferredTask.run(); - - verify(collector).requestDeadLockCheck(); - verify(view).setDeadLockInformation(null, "No Deadlocks Detected."); - } - - @Test - public void verifyInitializeSetsUpTimer() { - controller.initialize(); - - verify(timer).setAction(isA(Runnable.class)); - verify(timer).setDelay(5); - verify(timer).setInitialDelay(0); - verify(timer).setSchedulingType(SchedulingType.FIXED_DELAY); - verify(timer).setTimeUnit(TimeUnit.SECONDS); - } - - @Test - public void verifyTimerIsEnabledWhenViewIsVisible() { - controller.initialize(); - - ArgumentCaptor<ActionListener> listenerCaptor = (ArgumentCaptor<ActionListener>) ArgumentCaptor.forClass(ActionListener.class); - - verify(view).addActionListener(listenerCaptor.capture()); - - ActionListener<BasicView.Action> visibilityListener = listenerCaptor.getValue(); - - visibilityListener.actionPerformed(new ActionEvent<BasicView.Action>(view, Action.VISIBLE)); - - verify(timer).start(); - - visibilityListener.actionPerformed(new ActionEvent<BasicView.Action>(view, Action.HIDDEN)); - - verify(timer).stop(); - } - - @Test - public void verifyTimerActionRefreshesView() { - doThrow(new AssertionError()).when(collector).requestDeadLockCheck(); - - VmDeadLockData data = new VmDeadLockData("foo-agent"); - data.setDeadLockDescription(VmDeadLockData.NO_DEADLOCK); - controller.initialize(); - - when(collector.getLatestDeadLockData()).thenReturn(data); - - ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class); - verify(timer).setAction(runnableCaptor.capture()); - - Runnable action = runnableCaptor.getValue(); - - action.run(); - - verify(view).setDeadLockInformation(null, "No Deadlocks Detected."); - } - - @Test - public void verifyTimerActionHandlesNoDataCorrectly() { - doThrow(new AssertionError()).when(collector).requestDeadLockCheck(); - - controller.initialize(); - - when(collector.getLatestDeadLockData()).thenReturn(null); - - ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class); - verify(timer).setAction(runnableCaptor.capture()); - - Runnable action = runnableCaptor.getValue(); - - action.run(); - - // pass if no exceptions thrown - } - - @Test - public void verifyDeadlockControlEnabledWhenVmAlive() { - controller.initialize(); - verify(view).setCheckDeadlockControlEnabled(true); - } - - @Test - public void verifyDeadlockControlDisabledWhenVmDead() { - when(vmInfo.isAlive()).thenReturn(false); - controller.initialize(); - verify(view).setCheckDeadlockControlEnabled(false); - } -} -
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/cache/AppCacheKeyTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl.cache; - -import java.util.HashMap; -import java.util.Map; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -public class AppCacheKeyTest { - @Test - public void testEquals() throws Exception { - - AppCacheKey key1 = new AppCacheKey("test1", AppCacheKeyTest.class); - AppCacheKey key2 = new AppCacheKey("test2", AppCacheKeyTest.class); - - assertFalse(key1.equals(key2)); - - key2 = new AppCacheKey("test1", AppCacheKeyTest.class); - assertEquals(key1, key2); - - key1 = new AppCacheKey("test1", AppCacheKey.class); - key2 = new AppCacheKey("test1", AppCacheKeyTest.class); - assertFalse(key1.equals(key2)); - } - - @Test - public void testHashCode() throws Exception { - AppCacheKey key1 = new AppCacheKey("test1", AppCacheKeyTest.class); - AppCacheKey key2 = new AppCacheKey("test2", AppCacheKeyTest.class); - - assertFalse(key1.hashCode() == key2.hashCode()); - key2 = new AppCacheKey("test1", AppCacheKeyTest.class); - assertEquals(key1.hashCode(), key2.hashCode()); - } - - @Test - public void testInHashMap() { - Map<AppCacheKey, String> table = new HashMap<>(); - AppCacheKey key1 = new AppCacheKey("test1", AppCacheKeyTest.class); - table.put(key1, "1"); - - AppCacheKey key2 = new AppCacheKey("test2", AppCacheKeyTest.class); - table.put(key2, "1"); - - assertTrue(table.containsKey(key1)); - assertTrue(table.containsKey(key2)); - - assertEquals(table.get(key1), "1"); - assertEquals(table.get(key2), "1"); - - key1 = new AppCacheKey("test1", AppCacheKey.class); - table.put(key1, "1"); - - key2 = new AppCacheKey("test1", AppCacheKeyTest.class); - table.put(key2, "2"); - - assertTrue(table.containsKey(key1)); - assertTrue(table.containsKey(key2)); - - assertEquals(table.get(key1), "1"); - assertEquals(table.get(key2), "2"); - } -}
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/cache/AppCacheTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.controller.impl.cache; - -import com.redhat.thermostat.common.ApplicationCache; -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class AppCacheTest { - private ApplicationCache applicationCache; - private AppCacheKey key; - - @Before - public void setUp() { - this.key = new AppCacheKey("root", AppCache.class); - applicationCache = new ApplicationCache(); - } - - @Test - public void testCache() throws Exception { - AppCache cache = new AppCache(key, applicationCache); - - AppCacheKey key0 = new AppCacheKey("some-value-under-root-key", String.class); - cache.save(key0, "some-value-under-root-value"); - - String value = cache.retrieve(key0); - assertEquals(value, "some-value-under-root-value"); - - Object someValue = new Object(); - AppCacheKey key1 = new AppCacheKey("some-other-value-under-root-key", Object.class); - cache.save(key1, someValue); - - Object value2 = cache.retrieve(key1); - assertEquals(value2, someValue); - - cache.save(key1, "some-value-under-root-value"); - value = cache.retrieve(key1); - assertEquals(value, "some-value-under-root-value"); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/internal/LocaleResourcesTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal; + +import com.redhat.thermostat.testutils.AbstractLocaleResourcesTest; + +public class LocaleResourcesTest extends AbstractLocaleResourcesTest<LocaleResources> { + + @Override + protected Class<LocaleResources> getEnumClass() { + return LocaleResources.class; + } + + @Override + protected String getResourceBundle() { + return LocaleResources.RESOURCE_BUNDLE; + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/internal/LockControllerTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,127 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal; + +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +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.client.core.views.BasicView; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.thread.client.common.view.LockView; +import com.redhat.thermostat.thread.dao.LockInfoDao; +import com.redhat.thermostat.thread.model.LockInfo; + +public class LockControllerTest { + + private LockView view; + private Timer timer; + private LockInfoDao dao; + private VmRef vm; + + @Before + public void setup() { + view = mock(LockView.class); + timer = mock(Timer.class); + dao = mock(LockInfoDao.class); + vm = mock(VmRef.class); + } + + @Test + public void verifyVisibilityEnablesAndDisablesTimer() { + LockController controller = new LockController(view, timer, dao, vm); + controller.initialize(); + + ArgumentCaptor<ActionListener> actionListenerCaptor = ArgumentCaptor.forClass(ActionListener.class); + verify(view).addActionListener(actionListenerCaptor.capture()); + + ActionListener listener = actionListenerCaptor.getValue(); + listener.actionPerformed(new ActionEvent(view, BasicView.Action.VISIBLE)); + + verify(timer).start(); + + listener.actionPerformed(new ActionEvent(view, BasicView.Action.HIDDEN)); + + verify(timer).stop(); + } + + @Test + public void verifyViewIsNotUpdatedOnNoData() { + when(dao.getLatestLockInfo(vm)).thenReturn(null); + + LockController controller = new LockController(view, timer, dao, vm); + controller.initialize(); + + ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class); + verify(timer).setAction(captor.capture()); + Runnable updater = captor.getValue(); + + verify(view, never()).setLatestLockData(isA(LockInfo.class)); + + updater.run(); + + verify(view, never()).setLatestLockData(isA(LockInfo.class)); + } + + @Test + public void verifyViewIsUpdatedWithData() { + LockInfo lockInfo = new LockInfo(); + when(dao.getLatestLockInfo(vm)).thenReturn(lockInfo); + + LockController controller = new LockController(view, timer, dao, vm); + controller.initialize(); + + ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class); + verify(timer).setAction(captor.capture()); + Runnable updater = captor.getValue(); + + verify(view, never()).setLatestLockData(isA(LockInfo.class)); + + updater.run(); + + verify(view).setLatestLockData(lockInfo); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/internal/ThreadCountControllerTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,172 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.List; + +import org.jfree.chart.JFreeChart; +import org.jfree.data.xy.XYDataset; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.client.core.views.BasicView; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.thread.client.common.chart.LivingDaemonThreadDifferenceChart; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.client.common.view.ThreadCountView; +import com.redhat.thermostat.thread.model.SessionID; +import com.redhat.thermostat.thread.model.ThreadSession; +import com.redhat.thermostat.thread.model.ThreadSummary; + +import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner; + +// this is not a GUI test, but testGetThreadInformation uses AWT under the hood +@RunWith(CacioFESTRunner.class) +public class ThreadCountControllerTest { + + private Timer timer; + private Runnable threadAction; + private ThreadCountView view; + private ThreadCollector collector; + + private ActionListener<ThreadCountView.Action> actionListener; + + @Before + public void setUp() { + timer = mock(Timer.class); + view = mock(ThreadCountView.class); + collector = mock(ThreadCollector.class); + } + + @Test + public void testGetThreadInformation() { + + ArgumentCaptor<LivingDaemonThreadDifferenceChart> modelCaptor = + ArgumentCaptor.forClass(LivingDaemonThreadDifferenceChart.class); + + + ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class); + doNothing().when(timer).setAction(captor.capture()); + + ThreadCountController controller = new ThreadCountController(view, collector, timer); + controller.initialize(); + + ThreadSummary summary = mock(ThreadSummary.class); + when(summary.getTimeStamp()).thenReturn(5l); + when(summary.getCurrentLiveThreads()).thenReturn(42l); + when(summary.getCurrentDaemonThreads()).thenReturn(2l); + + ThreadSummary summary0 = mock(ThreadSummary.class); + when(summary0.getTimeStamp()).thenReturn(2l); + when(summary0.getCurrentLiveThreads()).thenReturn(43l); + when(summary0.getCurrentDaemonThreads()).thenReturn(1l); + + List<ThreadSummary> summaries = new ArrayList<>(); + summaries.add(summary); + summaries.add(summary0); + + SessionID lastSession = mock(SessionID.class); + when(collector.getLastThreadSession()).thenReturn(lastSession); + + when(collector.getLatestThreadSummary()).thenReturn(summary); + + List<ThreadSession> sessions = new ArrayList<>(); + when(collector.getThreadSessions(isA(Range.class))).thenReturn(sessions); + when(collector.getThreadSummary(isA(Range.class))).thenReturn(summaries); + + threadAction = captor.getValue(); + threadAction.run(); + + verify(collector).getLatestThreadSummary(); + + verify(view).setLiveThreads("42"); + verify(view).setDaemonThreads("2"); + + verify(view).updateLivingDaemonTimeline(modelCaptor.capture()); + LivingDaemonThreadDifferenceChart model = modelCaptor.getValue(); + + assertNotNull(model); + + JFreeChart chart = model.createChart(100, Color.BLACK); + XYDataset dataSet = chart.getXYPlot().getDataset(); + assertEquals(2, dataSet.getSeriesCount()); + + // total and living + assertEquals(2l, dataSet.getX(0, 0)); + assertEquals(5l, dataSet.getX(0, 1)); + + // the actual numbers + assertEquals(43.0, dataSet.getY(0, 0)); + assertEquals(42.0, dataSet.getY(0, 1)); + assertEquals(1.0, dataSet.getY(1, 0)); + assertEquals(2.0, dataSet.getY(1, 1)); + } + + @Test + public void testTimerStartAndStop() { + ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class); + doNothing().when(view).addActionListener(viewArgumentCaptor.capture()); + + ThreadCountController controller = new ThreadCountController(view, collector, timer); + controller.initialize(); + + actionListener = viewArgumentCaptor.getValue(); + actionListener.actionPerformed(new ActionEvent<>(view, BasicView.Action.VISIBLE)); + + verify(timer).start(); + + actionListener.actionPerformed(new ActionEvent<>(view, BasicView.Action.HIDDEN)); + + verify(timer).stop(); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/internal/ThreadInformationControllerTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,352 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.doNothing; +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.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.client.core.progress.ProgressNotifier; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.ApplicationCache; +import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.TimerFactory; +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.storage.core.HostRef; +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.dao.VmInfoDAO; +import com.redhat.thermostat.storage.model.VmInfo; +import com.redhat.thermostat.thread.client.common.ThreadTableBean; +import com.redhat.thermostat.thread.client.common.ThreadViewProvider; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory; +import com.redhat.thermostat.thread.client.common.view.LockView; +import com.redhat.thermostat.thread.client.common.view.ThreadCountView; +import com.redhat.thermostat.thread.client.common.view.ThreadTableView; +import com.redhat.thermostat.thread.client.common.view.ThreadTableView.ThreadSelectionAction; +import com.redhat.thermostat.thread.client.common.view.ThreadTimelineView; +import com.redhat.thermostat.thread.client.common.view.ThreadView; +import com.redhat.thermostat.thread.client.common.view.VmDeadLockView; +import com.redhat.thermostat.thread.dao.LockInfoDao; +import com.redhat.thermostat.thread.model.SessionID; +import com.redhat.thermostat.thread.model.ThreadSession; + +import junit.framework.Assert; + +public class ThreadInformationControllerTest { + + private ThreadView view; + + private ActionListener<ThreadTableView.ThreadSelectionAction> threadTableActionListener; + + private ThreadViewProvider viewFactory; + private ThreadInformationController controller; + + private ApplicationService appService; + private ExecutorService appExecutor; + + private VmInfo vmInfo; + private VmInfoDAO vmInfoDao; + private LockInfoDao lockInfoDao; + + private ThreadTableView threadTableView; + private VmDeadLockView deadLockView; + private ThreadTimelineView threadTimelineView; + private ThreadCountView threadCountView; + private LockView lockView; + + @Before + public void setUp() { + + appService = mock(ApplicationService.class); + vmInfo = mock(VmInfo.class); + when(vmInfo.isAlive()).thenReturn(true); + vmInfoDao = mock(VmInfoDAO.class); + when(vmInfoDao.getVmInfo(isA(VmRef.class))).thenReturn(vmInfo); + lockInfoDao = mock(LockInfoDao.class); + setUpTimers(); + setupCache(); + setupExecutor(); + setUpView(); + } + + private void setUpView() { + deadLockView = mock(VmDeadLockView.class); + threadTableView = mock(ThreadTableView.class); + threadTimelineView = mock(ThreadTimelineView.class); + threadCountView = mock(ThreadCountView.class); + lockView = mock(LockView.class); + + view = mock(ThreadView.class); + viewFactory = mock(ThreadViewProvider.class); + when(viewFactory.createView()).thenReturn(view); + + when(view.createDeadLockView()).thenReturn(deadLockView); + when(view.createThreadTableView()).thenReturn(threadTableView); + when(view.createThreadTimelineView()).thenReturn(threadTimelineView); + when(view.createThreadCountView()).thenReturn(threadCountView); + when(view.createLockView()).thenReturn(lockView); + + } + + private void setUpTimers() { + Timer timer = mock(Timer.class); + + TimerFactory timerFactory = mock(TimerFactory.class); + when(timerFactory.createTimer()).thenReturn(timer); + when(appService.getTimerFactory()).thenReturn(timerFactory); + } + + private void setupCache() { + ApplicationCache cache = mock(ApplicationCache.class); + when(appService.getApplicationCache()).thenReturn(cache); + } + + private void setupExecutor() { + appExecutor = mock(ExecutorService.class); + when(appService.getApplicationExecutor()).thenReturn(appExecutor); + } + + private void setUpListeners() { + doNothing().when(view).addActionListener(any(ActionListener.class)); + + ArgumentCaptor<ActionListener> threadTableViewCaptor = ArgumentCaptor.forClass(ActionListener.class); + doNothing().when(threadTableView).addThreadSelectionActionListener(threadTableViewCaptor.capture()); + + createController(); + + threadTableActionListener = threadTableViewCaptor.getValue(); + } + + private void createController() { + + VmRef ref = mock(VmRef.class); + HostRef agent = mock(HostRef.class); + when(ref.getHostRef()).thenReturn(agent); + when(agent.getAgentId()).thenReturn("0xcafe"); + + ThreadCollectorFactory collectorFactory = mock(ThreadCollectorFactory.class); + ThreadCollector collector = mock(ThreadCollector.class); + when(collectorFactory.getCollector(ref)).thenReturn(collector); + + ProgressNotifier notifier = mock(ProgressNotifier.class); + + controller = new ThreadInformationController(ref, appService, vmInfoDao, lockInfoDao, + collectorFactory, + viewFactory, notifier); + } + + @Test + public void verifyViewCreateSubViewCalled() { + + createController(); + + verify(view).createThreadTableView(); + verify(view).createDeadLockView(); + verify(view).createThreadTimelineView(); + verify(view).createThreadCountView(); + } + + @Test + public void verifyLiveRecording() { + + ActionListener<ThreadView.ThreadAction> threadActionListener; + ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class); + doNothing().when(view).addThreadActionListener(viewArgumentCaptor.capture()); + + VmRef ref = mock(VmRef.class); + when(ref.getVmId()).thenReturn("42"); + HostRef agent = mock(HostRef.class); + when(ref.getHostRef()).thenReturn(agent); + when(agent.getAgentId()).thenReturn("0xcafe"); + + ThreadCollector collector = mock(ThreadCollector.class); + when(collector.isHarvesterCollecting()).thenReturn(false).thenReturn(true); + when(collector.startHarvester()).thenReturn(true); + when(collector.stopHarvester()).thenReturn(true).thenReturn(false); + + ThreadCollectorFactory collectorFactory = mock(ThreadCollectorFactory.class); + when(collectorFactory.getCollector(ref)).thenReturn(collector); + + ProgressNotifier notifier = mock(ProgressNotifier.class); + + ArgumentCaptor<Runnable> longRunningTaskCaptor = ArgumentCaptor.forClass(Runnable.class); + doNothing().when(appExecutor).execute(longRunningTaskCaptor.capture()); + + controller = new ThreadInformationController(ref, appService, + vmInfoDao, lockInfoDao, + collectorFactory, + viewFactory, notifier); + + verify(collector).isHarvesterCollecting(); + verify(view, times(1)).setRecording(ThreadView.MonitoringState.STOPPED, false); + + // each action event posts a task to the executor. + // make sure the task is posted and execute it manually in tests to see its effects. + + threadActionListener = viewArgumentCaptor.getValue(); + threadActionListener.actionPerformed(new ActionEvent<>(view, ThreadView.ThreadAction.START_LIVE_RECORDING)); + + verify(appExecutor, times(1)).execute(isA(Runnable.class)); + longRunningTaskCaptor.getValue().run(); + + verify(view, times(1)).setRecording(ThreadView.MonitoringState.STARTING, false); + verify(view, times(1)).setRecording(ThreadView.MonitoringState.STARTED, false); + verify(collector).startHarvester(); + + threadActionListener.actionPerformed(new ActionEvent<>(view, ThreadView.ThreadAction.STOP_LIVE_RECORDING)); + + verify(appExecutor, times(2)).execute(isA(Runnable.class)); + longRunningTaskCaptor.getValue().run(); + + verify(collector).stopHarvester(); + verify(view, times(1)).setRecording(ThreadView.MonitoringState.STOPPING, false); + verify(view, times(2)).setRecording(ThreadView.MonitoringState.STOPPED, false); + + threadActionListener.actionPerformed(new ActionEvent<>(view, ThreadView.ThreadAction.STOP_LIVE_RECORDING)); + + verify(appExecutor, times(3)).execute(isA(Runnable.class)); + longRunningTaskCaptor.getValue().run(); + + verify(collector, times(2)).stopHarvester(); + verify(view, times(2)).setRecording(ThreadView.MonitoringState.STOPPING, false); + verify(view, times(3)).setRecording(ThreadView.MonitoringState.STOPPED, false); + } + + @Test + public void verifyRecordingControlDisabledForDeadVms() { + when(vmInfo.isAlive()).thenReturn(false); + + createController(); + + verify(view).setEnableRecordingControl(false); + } + + @Test + public void verifyTableViewLinksToDetailsView() { + setUpListeners(); + + ThreadTableBean bean = mock(ThreadTableBean.class); + + ActionEvent<ThreadSelectionAction> event = + new ActionEvent<>(threadTableView, ThreadSelectionAction.SHOW_THREAD_DETAILS); + event.setPayload(bean); + + threadTableActionListener.actionPerformed(event); + verify(view).displayThreadDetails(bean); + } + + @Test + public void verifySessionListDisplays() { + + ThreadCollector collector = mock(ThreadCollector.class); + List<ThreadSession> list = new ArrayList<>(); + list.add(mock(ThreadSession.class)); + list.add(mock(ThreadSession.class)); + + when(collector.getThreadSessions(any(Range.class))).thenReturn(list); + + ActionListener<ThreadView.ThreadAction> threadActionListener; + ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class); + doNothing().when(view).addThreadActionListener(viewArgumentCaptor.capture()); + + ArgumentCaptor<Runnable> taskCaptor = ArgumentCaptor.forClass(Runnable.class); + doNothing().when(appExecutor).execute(taskCaptor.capture()); + + createController(); + + controller.___injectCollectorForTesting(collector); + + threadActionListener = viewArgumentCaptor.getValue(); + ActionEvent<ThreadView.ThreadAction> action = new ActionEvent<>(view, ThreadView.ThreadAction.REQUEST_DISPLAY_RECORDED_SESSIONS); + threadActionListener.actionPerformed(action); + + Runnable runnable = taskCaptor.getValue(); + runnable.run(); + + ArgumentCaptor<List> listCaptor = ArgumentCaptor.forClass(List.class); + verify(view).displayTimelineSessionList(listCaptor.capture()); + + Assert.assertTrue(listCaptor.getValue().equals(list)); + } + + @Test + public void verifySessionLoads() { + + ThreadTimelineController timeline = mock(ThreadTimelineController.class); + ThreadTableController table = mock(ThreadTableController.class); + ThreadCountController count = mock(ThreadCountController.class); + LockController lock = mock(LockController.class); + VmDeadLockController deadLock = mock(VmDeadLockController.class); + + ThreadSession session = mock(ThreadSession.class); + SessionID id = mock(SessionID.class); + when(session.getSessionID()).thenReturn(id); + + ActionListener<ThreadView.ThreadAction> threadActionListener; + ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class); + doNothing().when(view).addThreadActionListener(viewArgumentCaptor.capture()); + + createController(); + + controller.___injectControllersForTesting(timeline, table, count, lock, deadLock); + + threadActionListener = viewArgumentCaptor.getValue(); + ActionEvent<ThreadView.ThreadAction> action = new ActionEvent<>(view, ThreadView.ThreadAction.REQUEST_LOAD_SESSION); + action.setPayload(session); + + threadActionListener.actionPerformed(action); + + verify(timeline).setSession(id); + verify(table).setSession(id); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/internal/ThreadTableControllerTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,99 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.client.common.view.ThreadTableView; + +public class ThreadTableControllerTest { + + private ThreadTableView view; + private ThreadCollector collector; + + private Timer timer; + + private ActionListener<ThreadTableView.Action> actionListener; + ArgumentCaptor<Runnable> timerActionCaptor; + + @Before + public void setUp() { + collector = mock(ThreadCollector.class); + + timer = mock(Timer.class); + + view = mock(ThreadTableView.class); + + setUpTimers(); + } + + private void setUpTimers() { + timer = mock(Timer.class); + timerActionCaptor = ArgumentCaptor.forClass(Runnable.class); + doNothing().when(timer).setAction(timerActionCaptor.capture()); + } + + @Test + public void testStartThreadTableController() { + + ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class); + doNothing().when(view).addActionListener(viewArgumentCaptor.capture()); + + ThreadTableController controller = new ThreadTableController(view, collector, timer); + controller.initialize(); + + actionListener = viewArgumentCaptor.getValue(); + actionListener.actionPerformed(new ActionEvent<>(view, ThreadTableView.Action.VISIBLE)); + + verify(timer).start(); + + actionListener.actionPerformed(new ActionEvent<>(view, ThreadTableView.Action.HIDDEN)); + + verify(timer).stop(); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/internal/ThreadTimelineControllerTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,190 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +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.common.Timer; +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.storage.core.experimental.statement.ResultHandler; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.client.common.model.timeline.ThreadInfo; +import com.redhat.thermostat.thread.client.common.view.ThreadTimelineView; +import com.redhat.thermostat.thread.model.SessionID; +import com.redhat.thermostat.thread.model.ThreadState; + +public class ThreadTimelineControllerTest { + + private ThreadTimelineView view; + private ThreadCollector collector; + private Timer timer; + private SessionID session; + + @Before + public void setup() { + view = mock(ThreadTimelineView.class); + collector = mock(ThreadCollector.class); + timer = mock(Timer.class); + session = mock(SessionID.class); + when(session.get()).thenReturn("42"); + when(collector.getLastThreadSession()).thenReturn(session); + } + + @Test + public void verifySession() { + ArgumentCaptor<Runnable> captor = + ArgumentCaptor.forClass(Runnable.class); + doNothing().when(timer).setAction(captor.capture()); + + ThreadTimelineController controller = + new ThreadTimelineController(view, collector, timer); + Runnable timerAction = captor.getValue(); + + timerAction.run(); + + verify(collector).getLastThreadSession(); + verify(collector).getThreadRange(session); + } + + @Test + public void verifySessionIfSet() { + ArgumentCaptor<Runnable> captor = + ArgumentCaptor.forClass(Runnable.class); + doNothing().when(timer).setAction(captor.capture()); + + SessionID newSession = mock(SessionID.class); + when(newSession.get()).thenReturn("0"); + + ThreadTimelineController controller = + new ThreadTimelineController(view, collector, timer); + Runnable timerAction = captor.getValue(); + + timerAction.run(); + + verify(collector).getThreadRange(session); + + controller.setSession(newSession); + + timerAction.run(); + + verify(collector).getThreadRange(newSession); + } + + @Test + public void verifyRange() { + ArgumentCaptor<Runnable> captor = + ArgumentCaptor.forClass(Runnable.class); + doNothing().when(timer).setAction(captor.capture()); + + Range<Long> range = new Range<>(0l, 10l); + when(collector.getThreadRange(session)).thenReturn(range); + + ThreadTimelineController controller = + new ThreadTimelineController(view, collector, timer); + Runnable timerAction = captor.getValue(); + + timerAction.run(); + + verify(collector).getThreadRange(session); + verify(view).setTotalRange(range); + } + + @Test + public void testAllBeansAreLoaded() { + ArgumentCaptor<Runnable> captor = + ArgumentCaptor.forClass(Runnable.class); + doNothing().when(timer).setAction(captor.capture()); + + ArgumentCaptor<ResultHandler> captor2 = + ArgumentCaptor.forClass(ResultHandler.class); + doNothing().when(collector).getThreadStates(any(SessionID.class), + captor2.capture(), + any(Range.class)); + + Range<Long> range = new Range<>(0l, 10l); + when(collector.getThreadRange(session)).thenReturn(range); + + ThreadTimelineController controller = + new ThreadTimelineController(view, collector, timer); + Runnable timerAction = captor.getValue(); + + timerAction.run(); + + ResultHandler handler = captor2.getValue(); + + ThreadState state0 = mock(ThreadState.class); + when(state0.getName()).thenReturn("state0"); + when(state0.getId()).thenReturn(0l); + when(state0.getState()).thenReturn("NEW"); + + ThreadState state1 = mock(ThreadState.class); + when(state1.getName()).thenReturn("state1"); + when(state1.getId()).thenReturn(1l); + when(state1.getState()).thenReturn("NEW"); + + ThreadState state2 = mock(ThreadState.class); + when(state2.getName()).thenReturn("state2"); + when(state2.getId()).thenReturn(2l); + when(state2.getState()).thenReturn("NEW"); + + handler.onResult(state0); + handler.onResult(state1); + handler.onResult(state2); + + ThreadInfo info = new ThreadInfo(); + info.setName("state0"); + info.setId(0l); + + verify(view).addThread(info); + + info.setName("state1"); + info.setId(1l); + verify(view).addThread(info); + + info.setName("state2"); + info.setId(2l); + verify(view).addThread(info); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/internal/VmDeadLockControllerTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,245 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal; + +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.client.core.progress.ProgressNotifier; +import com.redhat.thermostat.client.core.views.BasicView; +import com.redhat.thermostat.client.core.views.BasicView.Action; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.Timer.SchedulingType; +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.dao.VmInfoDAO; +import com.redhat.thermostat.storage.model.VmInfo; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.client.common.view.VmDeadLockView; +import com.redhat.thermostat.thread.client.common.view.VmDeadLockView.VmDeadLockViewAction; +import com.redhat.thermostat.thread.model.VmDeadLockData; + +public class VmDeadLockControllerTest { + + private VmInfoDAO vmInfoDao; + private VmInfo vmInfo; + private VmRef vmRef; + private Timer timer; + private VmDeadLockView view; + private ThreadCollector collector; + private ExecutorService executor; + private ProgressNotifier notifier; + + private VmDeadLockController controller; + + @Before + public void setUp() { + vmInfoDao = mock(VmInfoDAO.class); + + vmInfo = mock(VmInfo.class); + when(vmInfoDao.getVmInfo(isA(VmRef.class))).thenReturn(vmInfo); + when(vmInfo.isAlive()).thenReturn(true); + + vmRef = mock(VmRef.class); + + timer = mock(Timer.class); + + view = mock(VmDeadLockView.class); + + collector = mock(ThreadCollector.class); + + executor = mock(ExecutorService.class); + + notifier = mock(ProgressNotifier.class); + + controller = new VmDeadLockController(vmInfoDao, vmRef, view, collector, timer, executor, notifier); + } + + @Test + public void verifyInitilizeRegistersActionListener() { + controller.initialize(); + + verify(view).addVmDeadLockViewActionListener(isA(ActionListener.class)); + } + + @Test + public void verifyRealDeadLockDataIsDisplayedOnViewAction() { + final String DESCRIPTION = "foo bar"; + VmDeadLockData data = new VmDeadLockData("foo-agent"); + data.setDeadLockDescription(DESCRIPTION); + + ArgumentCaptor<Runnable> executionCaptor = ArgumentCaptor.forClass(Runnable.class); + doNothing().when(executor).execute(executionCaptor.capture()); + + controller.initialize(); + + ArgumentCaptor<ActionListener> listenerCaptor = (ArgumentCaptor<ActionListener>) ArgumentCaptor.forClass(ActionListener.class); + verify(view).addVmDeadLockViewActionListener(listenerCaptor.capture()); + + ActionListener<VmDeadLockViewAction> listener = (ActionListener<VmDeadLockViewAction>) listenerCaptor.getValue(); + + when(collector.getLatestDeadLockData()).thenReturn(data); + + listener.actionPerformed(new ActionEvent<VmDeadLockViewAction>(view, VmDeadLockViewAction.CHECK_FOR_DEADLOCK)); + + Runnable deferredTask = executionCaptor.getValue(); + deferredTask.run(); + + verify(collector).requestDeadLockCheck(); + verify(view).setDeadLockInformation(null, DESCRIPTION); + } + + @Test + public void verifyNoDeadLockDataIsDisplayedOnViewAction() { + VmDeadLockData data = new VmDeadLockData("foo-agent"); + data.setDeadLockDescription(VmDeadLockData.NO_DEADLOCK); + + ArgumentCaptor<Runnable> executionCaptor = ArgumentCaptor.forClass(Runnable.class); + doNothing().when(executor).execute(executionCaptor.capture()); + + controller.initialize(); + + ArgumentCaptor<ActionListener> listenerCaptor = (ArgumentCaptor<ActionListener>) ArgumentCaptor.forClass(ActionListener.class); + verify(view).addVmDeadLockViewActionListener(listenerCaptor.capture()); + + ActionListener<VmDeadLockViewAction> listener = (ActionListener<VmDeadLockViewAction>) listenerCaptor.getValue(); + + when(collector.getLatestDeadLockData()).thenReturn(data); + + listener.actionPerformed(new ActionEvent<VmDeadLockViewAction>(view, VmDeadLockViewAction.CHECK_FOR_DEADLOCK)); + + Runnable deferredTask = executionCaptor.getValue(); + deferredTask.run(); + + verify(collector).requestDeadLockCheck(); + verify(view).setDeadLockInformation(null, "No Deadlocks Detected."); + } + + @Test + public void verifyInitializeSetsUpTimer() { + controller.initialize(); + + verify(timer).setAction(isA(Runnable.class)); + verify(timer).setDelay(5); + verify(timer).setInitialDelay(0); + verify(timer).setSchedulingType(SchedulingType.FIXED_DELAY); + verify(timer).setTimeUnit(TimeUnit.SECONDS); + } + + @Test + public void verifyTimerIsEnabledWhenViewIsVisible() { + controller.initialize(); + + ArgumentCaptor<ActionListener> listenerCaptor = (ArgumentCaptor<ActionListener>) ArgumentCaptor.forClass(ActionListener.class); + + verify(view).addActionListener(listenerCaptor.capture()); + + ActionListener<BasicView.Action> visibilityListener = listenerCaptor.getValue(); + + visibilityListener.actionPerformed(new ActionEvent<BasicView.Action>(view, Action.VISIBLE)); + + verify(timer).start(); + + visibilityListener.actionPerformed(new ActionEvent<BasicView.Action>(view, Action.HIDDEN)); + + verify(timer).stop(); + } + + @Test + public void verifyTimerActionRefreshesView() { + doThrow(new AssertionError()).when(collector).requestDeadLockCheck(); + + VmDeadLockData data = new VmDeadLockData("foo-agent"); + data.setDeadLockDescription(VmDeadLockData.NO_DEADLOCK); + controller.initialize(); + + when(collector.getLatestDeadLockData()).thenReturn(data); + + ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(timer).setAction(runnableCaptor.capture()); + + Runnable action = runnableCaptor.getValue(); + + action.run(); + + verify(view).setDeadLockInformation(null, "No Deadlocks Detected."); + } + + @Test + public void verifyTimerActionHandlesNoDataCorrectly() { + doThrow(new AssertionError()).when(collector).requestDeadLockCheck(); + + controller.initialize(); + + when(collector.getLatestDeadLockData()).thenReturn(null); + + ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(timer).setAction(runnableCaptor.capture()); + + Runnable action = runnableCaptor.getValue(); + + action.run(); + + // pass if no exceptions thrown + } + + @Test + public void verifyDeadlockControlEnabledWhenVmAlive() { + controller.initialize(); + verify(view).setCheckDeadlockControlEnabled(true); + } + + @Test + public void verifyDeadlockControlDisabledWhenVmDead() { + when(vmInfo.isAlive()).thenReturn(false); + controller.initialize(); + verify(view).setCheckDeadlockControlEnabled(false); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/internal/cache/AppCacheKeyTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,102 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal.cache; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + +public class AppCacheKeyTest { + @Test + public void testEquals() throws Exception { + + AppCacheKey key1 = new AppCacheKey("test1", AppCacheKeyTest.class); + AppCacheKey key2 = new AppCacheKey("test2", AppCacheKeyTest.class); + + assertFalse(key1.equals(key2)); + + key2 = new AppCacheKey("test1", AppCacheKeyTest.class); + assertEquals(key1, key2); + + key1 = new AppCacheKey("test1", AppCacheKey.class); + key2 = new AppCacheKey("test1", AppCacheKeyTest.class); + assertFalse(key1.equals(key2)); + } + + @Test + public void testHashCode() throws Exception { + AppCacheKey key1 = new AppCacheKey("test1", AppCacheKeyTest.class); + AppCacheKey key2 = new AppCacheKey("test2", AppCacheKeyTest.class); + + assertFalse(key1.hashCode() == key2.hashCode()); + key2 = new AppCacheKey("test1", AppCacheKeyTest.class); + assertEquals(key1.hashCode(), key2.hashCode()); + } + + @Test + public void testInHashMap() { + Map<AppCacheKey, String> table = new HashMap<>(); + AppCacheKey key1 = new AppCacheKey("test1", AppCacheKeyTest.class); + table.put(key1, "1"); + + AppCacheKey key2 = new AppCacheKey("test2", AppCacheKeyTest.class); + table.put(key2, "1"); + + assertTrue(table.containsKey(key1)); + assertTrue(table.containsKey(key2)); + + assertEquals(table.get(key1), "1"); + assertEquals(table.get(key2), "1"); + + key1 = new AppCacheKey("test1", AppCacheKey.class); + table.put(key1, "1"); + + key2 = new AppCacheKey("test1", AppCacheKeyTest.class); + table.put(key2, "2"); + + assertTrue(table.containsKey(key1)); + assertTrue(table.containsKey(key2)); + + assertEquals(table.get(key1), "1"); + assertEquals(table.get(key2), "2"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/internal/cache/AppCacheTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,77 @@ +/* + * Copyright 2012-2016 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.thread.client.controller.internal.cache; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.common.ApplicationCache; + +public class AppCacheTest { + private ApplicationCache applicationCache; + private AppCacheKey key; + + @Before + public void setUp() { + this.key = new AppCacheKey("root", AppCache.class); + applicationCache = new ApplicationCache(); + } + + @Test + public void testCache() throws Exception { + AppCache cache = new AppCache(key, applicationCache); + + AppCacheKey key0 = new AppCacheKey("some-value-under-root-key", String.class); + cache.save(key0, "some-value-under-root-value"); + + String value = cache.retrieve(key0); + assertEquals(value, "some-value-under-root-value"); + + Object someValue = new Object(); + AppCacheKey key1 = new AppCacheKey("some-other-value-under-root-key", Object.class); + cache.save(key1, someValue); + + Object value2 = cache.retrieve(key1); + assertEquals(value2, someValue); + + cache.save(key1, "some-value-under-root-value"); + value = cache.retrieve(key1); + assertEquals(value, "some-value-under-root-value"); + } +}
--- a/thread/client-swing/pom.xml Wed Apr 06 14:52:26 2016 +0200 +++ b/thread/client-swing/pom.xml Fri Apr 08 13:18:48 2016 +0200 @@ -119,9 +119,9 @@ </Export-Package> <Private-Package> com.redhat.thermostat.thread.client.swing.osgi, - com.redhat.thermostat.thread.client.swing.impl, - com.redhat.thermostat.thread.client.swing.impl.timeline, - com.redhat.thermostat.thread.client.swing.impl.timeline.model, + com.redhat.thermostat.thread.client.swing.internal, + com.redhat.thermostat.thread.client.swing.internal.timeline, + com.redhat.thermostat.thread.client.swing.internal.timeline.model, com.redhat.thermostat.thread.client.swing.experimental.components, com.redhat.thermostat.thread.client.swing.experimental.utils, </Private-Package>
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/SwingThreadViewService.java Wed Apr 06 14:52:26 2016 +0200 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/SwingThreadViewService.java Fri Apr 08 13:18:48 2016 +0200 @@ -39,7 +39,7 @@ import com.redhat.thermostat.client.swing.UIDefaults; import com.redhat.thermostat.thread.client.common.ThreadViewProvider; import com.redhat.thermostat.thread.client.common.view.ThreadView; -import com.redhat.thermostat.thread.client.swing.impl.SwingThreadView; +import com.redhat.thermostat.thread.client.swing.internal.SwingThreadView; public class SwingThreadViewService implements ThreadViewProvider {
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingLockView.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,145 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl; - -import java.awt.BorderLayout; -import java.awt.Component; - -import javax.swing.JPanel; -import javax.swing.SwingUtilities; -import javax.swing.table.DefaultTableModel; - -import com.redhat.thermostat.client.swing.NonEditableTableModel; -import com.redhat.thermostat.client.swing.SwingComponent; -import com.redhat.thermostat.client.swing.components.ThermostatScrollPane; -import com.redhat.thermostat.client.swing.components.ThermostatTable; -import com.redhat.thermostat.client.swing.experimental.ComponentVisibilityNotifier; -import com.redhat.thermostat.shared.locale.Translate; -import com.redhat.thermostat.thread.client.common.locale.LocaleResources; -import com.redhat.thermostat.thread.client.common.view.LockView; -import com.redhat.thermostat.thread.model.LockInfo; - -public class SwingLockView extends LockView implements SwingComponent { - - protected static final String TABLE_NAME = "locks-table"; - - private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); - - private static final int VALUE_COLUMN = 1; - - private JPanel topPanel; - private ThermostatTable table; - private DefaultTableModel model; - - public SwingLockView() { - topPanel = new JPanel(); - topPanel.setLayout(new BorderLayout()); - - model = new NonEditableTableModel(18, 2); - Object[][] dataVector = new Object[][] { - new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_CONTENDED_LOCK_ATTEMPS).getContents(), 0 }, - new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_DEFLATIONS).getContents(), 0 }, - new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_EMPTY_NOTIFICATIONS).getContents(), 0 }, - new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_FAILED_SPINS).getContents(), 0 }, - new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_FUTILE_WAKEUPS).getContents(), 0 }, - new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_INFLATIONS).getContents(), 0 }, - new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_MON_EXTANT).getContents(), 0 }, - new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_MON_IN_CIRCULATION).getContents(), 0 }, - new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_MON_SCAVENGED).getContents(), 0 }, - new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_NOTIFICATIONS).getContents(), 0 }, - new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_PARKS).getContents(), 0 }, - new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_PRIVATE_A).getContents(), 0 }, - new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_PRIVATE_B).getContents(), 0 }, - new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_SLOW_ENTER).getContents(), 0 }, - new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_SLOW_EXIT).getContents(), 0 }, - new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_SLOW_NOTIFY).getContents(), 0 }, - new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_SLOW_NOTIFY_ALL).getContents(), 0 }, - new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_SUCCESSFUL_SPINS).getContents(), 0 }, - }; - - Object[] columnIdentifiers = new Object[] { - translator.localize(LocaleResources.LOCK_COLUMN_NAME).getContents(), - translator.localize(LocaleResources.LOCK_COLUMN_VALUE).getContents()}; - model.setDataVector(dataVector, columnIdentifiers); - - table = new ThermostatTable(model); - table.setName(TABLE_NAME); - - ThermostatScrollPane scrollPane = new ThermostatScrollPane(table); - topPanel.add(scrollPane, BorderLayout.CENTER); - - new ComponentVisibilityNotifier().initialize(topPanel, notifier); - } - - @Override - public void setLatestLockData(final LockInfo data) { - SwingUtilities.invokeLater(new Runnable() { - private int row = 0; - @Override - public void run() { - updateModel(data.getContendedLockAttempts()); - updateModel(data.getDeflations()); - updateModel(data.getEmptyNotifications()); - updateModel(data.getFailedSpins()); - updateModel(data.getFutileWakeups()); - updateModel(data.getInflations()); - updateModel(data.getMonExtant()); - updateModel(data.getMonInCirculation()); - updateModel(data.getMonScavenged()); - updateModel(data.getNotifications()); - updateModel(data.getParks()); - updateModel(data.getPrivateA()); - updateModel(data.getPrivateB()); - updateModel(data.getSlowEnter()); - updateModel(data.getSlowExit()); - updateModel(data.getSlowNotify()); - updateModel(data.getSlowNotifyAll()); - updateModel(data.getSuccessfulSpins()); - } - - private void updateModel(long number) { - model.setValueAt(number, row, VALUE_COLUMN); - row++; - } - }); - } - @Override - public Component getUiComponent() { - return topPanel; - } - -}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadCountView.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl; - -import com.redhat.thermostat.client.swing.ComponentVisibleListener; -import com.redhat.thermostat.client.swing.SwingComponent; -import com.redhat.thermostat.client.swing.components.ChartPanel; -import com.redhat.thermostat.thread.client.common.chart.LivingDaemonThreadDifferenceChart; -import com.redhat.thermostat.thread.client.common.view.ThreadCountView; - -import javax.swing.JPanel; -import javax.swing.SwingUtilities; -import javax.swing.SwingWorker; -import java.awt.Component; - -public class SwingThreadCountView extends ThreadCountView implements SwingComponent { - - private ThreadAliveDaemonTimelinePanel timelinePanel; - - public SwingThreadCountView() { - timelinePanel = new ThreadAliveDaemonTimelinePanel(); - timelinePanel.addHierarchyListener(new ComponentVisibleListener() { - @Override - public void componentShown(Component component) { - SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { - @Override - protected Void doInBackground() throws Exception { - SwingThreadCountView.this.notify(Action.VISIBLE); - return null; - } - }; - worker.execute(); - } - - @Override - public void componentHidden(Component component) { - SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { - @Override - protected Void doInBackground() throws Exception { - SwingThreadCountView.this.notify(Action.HIDDEN); - return null; - } - }; - worker.execute(); - } - }); - } - - public void setLiveThreads(final String liveThreads) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - timelinePanel.getLiveThreads().setText(liveThreads); - } - }); - }; - - @Override - public void updateLivingDaemonTimeline(final LivingDaemonThreadDifferenceChart model) - { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - JPanel pane = timelinePanel.getTimelinePanel(); - pane.removeAll(); - - ChartPanel charts = new ChartPanel(model.createChart(pane.getWidth(), pane.getBackground())); - charts.setName("threadChartPanel"); - pane.add(charts); - pane.revalidate(); - pane.repaint(); - } - }); - } - - @Override - public void setDaemonThreads(final String daemonThreads) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - timelinePanel.getDaemonThreads().setText(daemonThreads); - } - }); - } - - @Override - public Component getUiComponent() { - return timelinePanel; - } -} -
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadDetailsView.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl; - -import java.awt.BorderLayout; -import java.awt.Component; - -import javax.swing.ImageIcon; -import javax.swing.JLabel; -import javax.swing.JPanel; - -import com.redhat.thermostat.client.swing.SwingComponent; -import com.redhat.thermostat.client.swing.components.ChartPanel; -import com.redhat.thermostat.shared.locale.Translate; -import com.redhat.thermostat.thread.client.common.ThreadTableBean; -import com.redhat.thermostat.thread.client.common.chart.ThreadDeatailsPieChart; -import com.redhat.thermostat.thread.client.common.locale.LocaleResources; -import com.redhat.thermostat.thread.client.common.view.ThreadDetailsView; - -public class SwingThreadDetailsView extends ThreadDetailsView implements SwingComponent { - - private JPanel details; - private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); - - SwingThreadDetailsView() { - details = new JPanel(); - details.setLayout(new BorderLayout(0, 0)); - - JLabel lblNewLabel = new JLabel(t.localize(LocaleResources.THREAD_DETAILS_EMTPY).getContents()); - lblNewLabel.setIcon(new ImageIcon(getEmptyDetailsIcon().getData().array())); - details.add(lblNewLabel); - } - - @Override - public Component getUiComponent() { - return details; - } - - @Override - public void setDetails(ThreadTableBean thread) { - details.removeAll(); - - ThreadDetailsChart threadChart = new ThreadDetailsChart(); - - ChartPanel threadSummary = new ChartPanel(new ThreadDeatailsPieChart(thread).createChart()); - threadChart.add(threadSummary); - - details.add(threadChart); - details.repaint(); - } -} -
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadTableView.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,308 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl; - -import com.redhat.thermostat.client.swing.NonEditableTableModel; -import com.redhat.thermostat.client.swing.SwingComponent; -import com.redhat.thermostat.client.swing.components.ThermostatTable; -import com.redhat.thermostat.client.swing.experimental.ComponentVisibilityNotifier; -import com.redhat.thermostat.shared.locale.Translate; -import com.redhat.thermostat.thread.client.common.ThreadTableBean; -import com.redhat.thermostat.thread.client.common.locale.LocaleResources; -import com.redhat.thermostat.thread.client.common.view.ThreadTableView; - -import java.awt.Component; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.swing.SwingUtilities; -import javax.swing.SwingWorker; -import javax.swing.event.TableModelEvent; -import javax.swing.event.TableModelListener; - -public class SwingThreadTableView extends ThreadTableView implements SwingComponent { - - private boolean tableRepacked = false; - - private int currentSelection = -1; - - private ThermostatTable table; - private ThreadTable tablePanel; - - private Map<ThreadTableBean, Integer> beans; - - private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); - - public SwingThreadTableView() { - - beans = new HashMap<>(); - tablePanel = new ThreadTable(); - new ComponentVisibilityNotifier().initialize(tablePanel, notifier); - - table = new ThermostatTable(new ThreadViewTableModel()); - table.setName("threadBeansTable"); - table.getModel().addTableModelListener(new TableModelListener() { - @Override - public void tableChanged(TableModelEvent e) { - // NOTE: The fireTableDataChanged executes this listener - // before the internal listener, this means this update will - // be overridden since the default listener resets the model. - // So, although we are in the EDT, we need to ensure that - // we schedule this operation for later, rather than do it - // right away... isn't Swing fun? - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - if (currentSelection != -1) { - table.setRowSelectionInterval(currentSelection, currentSelection); - } - } - }); - } - }); - tablePanel.add(table.wrap()); - - table.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() == 2) { - ThreadViewTableModel model = (ThreadViewTableModel) table.getModel(); - int selectedRow = table.getSelectedRow(); - if (selectedRow != -1) { - selectedRow = table.convertRowIndexToModel(selectedRow); - final ThreadTableBean bean = model.infos.get(selectedRow); - SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { - protected Void doInBackground() throws Exception { - threadTableNotifier.fireAction(ThreadSelectionAction.SHOW_THREAD_DETAILS, bean); - return null; - } - }; - worker.execute(); - } - } - } - }); - } - - @Override - public void clear() { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - ThreadViewTableModel model = (ThreadViewTableModel) table.getModel(); - model.setRowCount(0); - beans.clear(); - } - }); - } - - @Override - public Component getUiComponent() { - return tablePanel; - } - - @Override - public void display(final ThreadTableBean tableBean) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - - // reset the selection for the next iteration - // everything is happening in one thread, so there's no fear - currentSelection = -1; - - ThreadViewTableModel model = (ThreadViewTableModel) table.getModel(); - int selectedRow = table.getSelectedRow(); - - ThreadTableBean info = null; - if (selectedRow != -1) { - info = model.infos.get(selectedRow); - } - - // update the infos - Integer beanIndex = beans.get(tableBean); - if (beanIndex == null) { - beanIndex = Integer.valueOf(model.infos.size()); - beans.put(tableBean, beanIndex); - model.infos.add(tableBean); - } - - if (info != null) { - int index = 0; - for (ThreadTableBean inModel : model.infos) { - if (info.equals(inModel)) { - currentSelection = index; - break; - } - index++; - } - } - - // just repack once, or the user will see the table moving around - if (!tableRepacked) { - table.repackCells(); - tableRepacked = true; - } - } - }); - } - - @Override - public void submitChanges() { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - ThreadViewTableModel model = - (ThreadViewTableModel) table.getModel(); - model.fireTableDataChanged(); - } - }); - } - - @SuppressWarnings("serial") - private class ThreadViewTableModel extends NonEditableTableModel { - - private String [] columns = { - t.localize(LocaleResources.NAME).getContents(), - t.localize(LocaleResources.ID).getContents(), - t.localize(LocaleResources.FIRST_SEEN).getContents(), - t.localize(LocaleResources.LAST_SEEN).getContents(), - t.localize(LocaleResources.WAIT_COUNT).getContents(), - t.localize(LocaleResources.BLOCK_COUNT).getContents(), - t.localize(LocaleResources.RUNNING).getContents(), - t.localize(LocaleResources.WAITING).getContents(), - t.localize(LocaleResources.SLEEPING).getContents(), - t.localize(LocaleResources.MONITOR).getContents(), //, "Heap", "CPU Time", "User CPU Time" - }; - - private List<ThreadTableBean> infos; - public ThreadViewTableModel() { - this.infos = new ArrayList<>(); - } - - @Override - public String getColumnName(int column) { - return columns[column]; - } - - @Override - public int getColumnCount() { - return columns.length; - } - - @Override - public int getRowCount() { - if (infos == null) { - return 0; - } - return infos.size(); - } - - @Override - public Class<?> getColumnClass(int column) { - switch (column) { - case 0: - case 2: - case 3: - case 6: - case 7: - case 8: - case 9: - return String.class; - default: - return Long.class; - } - } - - @Override - public Object getValueAt(int row, int column) { - - DecimalFormat format = new DecimalFormat("###.00"); - - Object result = null; - - ThreadTableBean info = infos.get(row); - switch (column) { - case 0: - result = info.getName(); - break; - case 1: - result = info.getId(); - break; - case 2: - result = new Date(info.getStartTimeStamp()).toString(); - break; - case 3: - if (info.getStopTimeStamp() != 0) { - result = new Date(info.getStopTimeStamp()).toString(); - } else { - result = "-"; - } - break; - case 4: - result = info.getWaitedCount(); - break; - case 5: - result = info.getBlockedCount(); - break; - case 6: - result = format.format(info.getRunningPercent()); - break; - case 7: - result = format.format(info.getWaitingPercent()); - break; - case 8: - result = format.format(info.getSleepingPercent()); - break; - case 9: - result = format.format(info.getMonitorPercent()); - break; - default: - result = "n/a"; - break; - } - return result; - } - } -} -
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadTimelineView.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,167 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl; - -import com.redhat.thermostat.client.swing.SwingComponent; -import com.redhat.thermostat.client.swing.UIDefaults; -import com.redhat.thermostat.client.swing.experimental.ComponentVisibilityNotifier; -import com.redhat.thermostat.common.model.Range; -import com.redhat.thermostat.thread.client.common.model.timeline.ThreadInfo; -import com.redhat.thermostat.thread.client.common.model.timeline.TimelineProbe; -import com.redhat.thermostat.thread.client.common.view.ThreadTimelineView; -import com.redhat.thermostat.thread.client.swing.experimental.utils.EDTHelper; -import com.redhat.thermostat.thread.client.swing.impl.timeline.RangeComponent; -import com.redhat.thermostat.thread.client.swing.impl.timeline.TimelineComponent; -import com.redhat.thermostat.thread.client.swing.impl.timeline.TimelineContainer; -import com.redhat.thermostat.thread.client.swing.impl.timeline.TimelineViewComponent; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.RangedTimelineProbe; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.TimelineDateFormatter; -import java.awt.Component; -import java.util.HashMap; -import java.util.Map; - -public class SwingThreadTimelineView extends ThreadTimelineView implements SwingComponent { - - private final UIDefaults uiDefaults; - private TimelineViewComponent contentPane; - - private ComponentVisibilityNotifier visibilityNotifier; - - private Map<ThreadInfo, TimelineComponent> timelines; - - private EDTHelper edt; - - public SwingThreadTimelineView(UIDefaults uiDefaults) { - this.uiDefaults = uiDefaults; - - edt = new EDTHelper(); - timelines = new HashMap<>(); - - this.contentPane = new TimelineViewComponent(uiDefaults); - clear(); - - visibilityNotifier = new ComponentVisibilityNotifier(); - visibilityNotifier.initialize(contentPane, notifier); - } - - @Override - public void addThread(final ThreadInfo thread) { - edt.callLater(new Runnable() { - @Override - public void run() { - if (!timelines.containsKey(thread)) { - TimelineComponent timeline = - new TimelineComponent(uiDefaults, thread, - contentPane.getModel()); - timeline.initComponents(); - - timelines.put(thread, timeline); - contentPane.addTimeline(timeline); - } - } - }); - } - - @Override - public Component getUiComponent() { - return contentPane; - } - - @Override - public void setTotalRange(final Range<Long> totalRange) { - edt.callLater(new Runnable() { - @Override - public void run() { - contentPane.getModel().setRange(totalRange); - } - }); - } - - @Override - public void clear() { - edt.callLater(new Runnable() { - @Override - public void run() { - timelines.clear(); - contentPane.removeAll(); - contentPane.initComponents(); - contentPane.revalidate(); - contentPane.repaint(); - } - }); - } - - @Override - public void addProbe(final ThreadInfo info, final TimelineProbe state) { - edt.callLater(new Runnable() { - @Override - public void run() { - TimelineComponent component = timelines.get(info); - TimelineContainer timelineContainer = - component.getTimelineContainer(); - RangeComponent rangeComponent = - timelineContainer.getLastRangeComponent(); - - if (rangeComponent == null) { - setRangedComponent(state, timelineContainer); - - } else { - RangedTimelineProbe probe = rangeComponent.getInfo(); - probe.setProbeEnd(state.getTimeStamp()); - if (!probe.getColor().equals(state.getColor())) { - setRangedComponent(state, timelineContainer); - } - } - timelineContainer.revalidate(); - timelineContainer.repaint(); - } - }); - } - - private void setRangedComponent(TimelineProbe state, - TimelineContainer timelineContainer) - { - RangedTimelineProbe probe = - new RangedTimelineProbe(state, state.getTimeStamp()); - RangeComponent rangeComponent = new RangeComponent(probe); - rangeComponent.setToolTipText(state.getState() + " - " + - TimelineDateFormatter.format(state. - getTimeStamp())); - timelineContainer.add(rangeComponent); - } -} -
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadView.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,334 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl; - -import com.redhat.thermostat.client.swing.ComponentVisibleListener; -import com.redhat.thermostat.client.swing.SwingComponent; -import com.redhat.thermostat.client.swing.UIDefaults; -import com.redhat.thermostat.client.swing.components.ThermostatTabbedPane; -import com.redhat.thermostat.common.ApplicationService; -import com.redhat.thermostat.shared.locale.LocalizedString; -import com.redhat.thermostat.shared.locale.Translate; -import com.redhat.thermostat.thread.client.common.ThreadTableBean; -import com.redhat.thermostat.thread.client.common.locale.LocaleResources; -import com.redhat.thermostat.thread.client.common.view.LockView; -import com.redhat.thermostat.thread.client.common.view.ThreadCountView; -import com.redhat.thermostat.thread.client.common.view.ThreadTableView; -import com.redhat.thermostat.thread.client.common.view.ThreadTimelineView; -import com.redhat.thermostat.thread.client.common.view.ThreadView; -import com.redhat.thermostat.thread.client.common.view.VmDeadLockView; -import com.redhat.thermostat.thread.model.ThreadSession; - -import javax.swing.JOptionPane; -import javax.swing.JSplitPane; -import javax.swing.JTabbedPane; -import javax.swing.SwingUtilities; -import javax.swing.SwingWorker; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; -import java.awt.Component; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.util.List; - -public class SwingThreadView extends ThreadView implements SwingComponent { - - private String DIVIDER_LOCATION_KEY; - - private ThreadMainPanel panel; - - private SwingThreadCountView threadCountView; - private SwingThreadTableView threadTableView; - private SwingVmDeadLockView vmDeadLockView; - private SwingThreadTimelineView threadTimelineView; - private SwingThreadDetailsView threadDetailsView; - private SwingLockView lockView; - - private JTabbedPane topPane; - private JTabbedPane bottomPane; - - private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); - - private boolean skipNotification = false; - - private int threadDetailsPaneID = 0; - - private UIDefaults uiDefaults; - private boolean viewControlsEnabled = true; - - - public SwingThreadView(UIDefaults uiDefaults) { - - this.uiDefaults = uiDefaults; - - panel = new ThreadMainPanel(uiDefaults); - // TODO use ComponentVisiblityNotifier instead - // sadly, the BasicView.notifier field can not be accessed here - panel.addHierarchyListener(new ComponentVisibleListener() { - - @Override - public void componentShown(Component component) { - SwingThreadView.this.notify(Action.VISIBLE); - restoreDivider(); - } - - @Override - public void componentHidden(Component component) { - SwingThreadView.this.notify(Action.HIDDEN); - } - }); - - panel.getSplitPane().addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, - new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - JSplitPane sourceSplitPane = (JSplitPane) evt.getSource(); - saveDivider(sourceSplitPane.getDividerLocation()); - } - }); - - panel.getRecordingToggleButton().setToolTipText(t.localize(LocaleResources.START_RECORDING).getContents()); - panel.getRecordingToggleButton().addItemListener(new ItemListener() - { - @Override - public void itemStateChanged(ItemEvent e) { - - ThreadAction action = null; - if (e.getStateChange() == ItemEvent.SELECTED) { - action = ThreadAction.START_LIVE_RECORDING; - panel.getRecordingToggleButton().setToolTipText(t.localize(LocaleResources.STOP_RECORDING).getContents()); - } else { - action = ThreadAction.STOP_LIVE_RECORDING; - panel.getRecordingToggleButton().setToolTipText(t.localize(LocaleResources.START_RECORDING).getContents()); - } - - if (skipNotification) return; - - final ThreadAction toNotify = action; - SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { - @Override - protected Void doInBackground() throws Exception { - notifier.fireAction(toNotify); - return null; - } - }; - worker.execute(); - } - }); - - panel.getShowRecordedSessionsButton().setToolTipText(t.localize(LocaleResources.RECORDING_LIST_HINT).getContents()); - panel.getShowRecordedSessionsButton().addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - if (e.getStateChange() != ItemEvent.SELECTED) { - panel.toggleOverlayPanel(false); - return; - } - - SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { - @Override - protected Void doInBackground() throws Exception { - notifier.fireAction(ThreadAction.REQUEST_DISPLAY_RECORDED_SESSIONS); - return null; - } - }; - worker.execute(); - } - }); - - panel.getSessionsPanel().addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - notifier.fireAction(ThreadAction.REQUEST_LOAD_SESSION, - panel.getSessionsPanel().getSelectedValue()); - } - }); - setupTopPane(); - setupBottomPane(); - } - - private void setupTopPane() { - topPane = new ThermostatTabbedPane(); - topPane.setName("topTabbedPane"); - - threadCountView = new SwingThreadCountView(); - Component comp = threadCountView.getUiComponent(); - comp.setName("count"); - topPane.addTab(t.localize(LocaleResources.THREAD_COUNT).getContents(), comp); - - threadTimelineView = new SwingThreadTimelineView(uiDefaults); - comp = threadTimelineView.getUiComponent(); - comp.setName("timeline"); - topPane.addTab(t.localize(LocaleResources.TIMELINE).getContents(), comp); - - lockView = new SwingLockView(); - comp = lockView.getUiComponent(); - comp.setName("lock"); - topPane.addTab(t.localize(LocaleResources.LOCKS).getContents(), comp); - - panel.getSplitPane().setTopComponent(topPane); - } - - private void setupBottomPane() { - bottomPane = new ThermostatTabbedPane(); - bottomPane.setName("bottomTabbedPane"); - - threadTableView = new SwingThreadTableView(); - bottomPane.addTab(t.localize(LocaleResources.TABLE).getContents(), threadTableView.getUiComponent()); - - threadDetailsView = new SwingThreadDetailsView(); - bottomPane.addTab(t.localize(LocaleResources.DETAILS).getContents(), threadDetailsView.getUiComponent()); - threadDetailsPaneID = 1; - - vmDeadLockView = new SwingVmDeadLockView(); - bottomPane.addTab(t.localize(LocaleResources.VM_DEADLOCK).getContents(), vmDeadLockView.getUiComponent()); - - panel.getSplitPane().setBottomComponent(bottomPane); - } - - @Override - public Component getUiComponent() { - return panel; - } - - @Override - public void setApplicationService(ApplicationService appService, String uniqueId) { - super.setApplicationService(appService, uniqueId); - DIVIDER_LOCATION_KEY = "divider." + uniqueId; - } - - @Override - public void setEnableRecordingControl(final boolean enable) { - this.viewControlsEnabled = enable; - if (!enable) { - setRecording(MonitoringState.DISABLED, false); - } - } - - @Override - public void setRecording(final MonitoringState monitoringState, final boolean notify) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - if (!notify) skipNotification = true; - if (!viewControlsEnabled) { - panel.getRecordingToggleButton().setToggleActionState(MonitoringState.DISABLED); - } else { - panel.getRecordingToggleButton().setToggleActionState(monitoringState); - } - if (!notify) skipNotification = false; - } - }); - } - - @Override - public VmDeadLockView createDeadLockView() { - return vmDeadLockView; - } - - @Override - public ThreadTableView createThreadTableView() { - return threadTableView; - } - - @Override - public void displayWarning(final LocalizedString warning) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - JOptionPane.showMessageDialog(panel.getParent(), warning.getContents(), "", JOptionPane.WARNING_MESSAGE); - } - }); - } - - private void restoreDivider() { - int location = (int) ((double) (panel.getSplitPane().getHeight() - panel.getSplitPane().getDividerSize()) * 0.80); - if (appService != null) { - Object _location = appService.getApplicationCache().getAttribute(DIVIDER_LOCATION_KEY); - if (_location != null) { - location = (Integer) _location; - } - } - panel.getSplitPane().setDividerLocation(location); - } - - private void saveDivider(int location) { - if (appService != null) { - appService.getApplicationCache().addAttribute(DIVIDER_LOCATION_KEY, location); - } - } - - @Override - public void displayThreadDetails(final ThreadTableBean thread) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - bottomPane.setSelectedIndex(threadDetailsPaneID); - threadDetailsView.setDetails(thread); - } - }); - } - - @Override - public ThreadTimelineView createThreadTimelineView() { - return threadTimelineView; - } - - @Override - public ThreadCountView createThreadCountView() { - return threadCountView; - } - - @Override - public LockView createLockView() { - return lockView; - } - - @Override - public void displayTimelineSessionList(final List<ThreadSession> threadSessions) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - panel.setOverlayContent(threadSessions); - panel.toggleOverlayPanel(true); - } - }); - } -} -
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingVmDeadLockView.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,328 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl; - -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.FontMetrics; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.Serializable; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import javax.swing.JButton; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JSplitPane; -import javax.swing.SwingUtilities; - -import com.mxgraph.layout.mxCircleLayout; -import com.mxgraph.layout.mxEdgeLabelLayout; -import com.mxgraph.layout.mxGraphLayout; -import com.mxgraph.model.mxCell; -import com.mxgraph.swing.mxGraphComponent; -import com.mxgraph.util.mxConstants; -import com.mxgraph.view.mxGraph; -import com.redhat.thermostat.client.swing.SwingComponent; -import com.redhat.thermostat.client.swing.components.ThermostatScrollBar; -import com.redhat.thermostat.client.swing.components.ThermostatScrollPane; -import com.redhat.thermostat.client.swing.components.ThermostatTextArea; -import com.redhat.thermostat.client.swing.experimental.ComponentVisibilityNotifier; -import com.redhat.thermostat.common.utils.StringUtils; -import com.redhat.thermostat.shared.locale.Translate; -import com.redhat.thermostat.thread.client.common.DeadlockParser; -import com.redhat.thermostat.thread.client.common.DeadlockParser.Information; -import com.redhat.thermostat.thread.client.common.locale.LocaleResources; -import com.redhat.thermostat.thread.client.common.view.VmDeadLockView; - -public class SwingVmDeadLockView extends VmDeadLockView implements SwingComponent { - - private static final Translate<LocaleResources> translate = LocaleResources.createLocalizer(); - - private final JPanel actualComponent = new JPanel(); - private final JButton checkForDeadlockButton; - - private final JSplitPane deadlockTextAndVisualization = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); - - private final JPanel graphical = new JPanel(); - private final ThermostatTextArea description = new ThermostatTextArea(); - /** - * Whether to set the divider's location. Do this only once to set a sane - * initial value but don't change anything after and allow the user to tweak - * this as appropriate. - */ - private boolean dividerLocationSet = false; - - public SwingVmDeadLockView() { - actualComponent.setLayout(new GridBagLayout()); - - GridBagConstraints c = new GridBagConstraints(); - c.gridy = 0; - c.anchor = GridBagConstraints.LINE_END; - checkForDeadlockButton = new JButton(translate.localize(LocaleResources.CHECK_FOR_DEADLOCKS).getContents()); - checkForDeadlockButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - deadLockNotifier.fireAction(VmDeadLockViewAction.CHECK_FOR_DEADLOCK); - } - }); - - actualComponent.add(checkForDeadlockButton, c); - - c.anchor = GridBagConstraints.LINE_START; - c.gridy++; - c.fill = GridBagConstraints.BOTH; - c.weightx = 1; - c.weighty = 1; - - description.setEditable(false); - - JScrollPane scrollPane = new ThermostatScrollPane(description); - - graphical.setLayout(new BorderLayout()); - - deadlockTextAndVisualization.setLeftComponent(scrollPane); - deadlockTextAndVisualization.setRightComponent(graphical); - - actualComponent.add(deadlockTextAndVisualization, c); - - new ComponentVisibilityNotifier().initialize(actualComponent, notifier); - } - - @Override - public void setDeadLockInformation(final Information parsed, final String rawText) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - - graphical.removeAll(); - - if (!dividerLocationSet) { - // 0.7 is chosen empirically to show a bit more of the text than the gui - deadlockTextAndVisualization.setDividerLocation(0.7); - deadlockTextAndVisualization.revalidate(); - dividerLocationSet = true; - } - - if (parsed != null) { - FontMetrics metrics = graphical.getGraphics().getFontMetrics(); - graphical.add(createGraph(parsed, metrics), BorderLayout.CENTER); - } - - graphical.revalidate(); - graphical.repaint(); - - description.setText(rawText); - } - }); - } - - private mxGraphComponent createGraph(Information info, FontMetrics fontMetrics) { - - final mxGraph graph = new mxGraph() { - - /* Show tooltips for vertices and edges */ - @Override - public String getToolTipForCell(Object source) { - mxCell cell = ((mxCell) source); - - if (cell.getValue() instanceof GraphItem) { - return ((GraphItem) cell.getValue()).getTooltip(); - } else { - return super.getToolTipForCell(cell); - } - } - - - /* Prevent modifying the contents of edges or vertices */ - @Override - public boolean isCellEditable(Object cell) { - return false; - } - - /* Prevent moving edges away from the vertices */ - @Override - public boolean isCellSelectable(Object cell) { - return !model.isEdge(cell); - } - - }; - - Object parent = graph.getDefaultParent(); - - addDeadlockToGraph(info, graph, parent, fontMetrics); - - graph.setAutoSizeCells(true); - graph.setCellsResizable(true); - - final mxGraphComponent graphComponent = new mxGraphComponent(graph); - graphComponent.setTextAntiAlias(true); - graphComponent.setToolTips(true); - graphComponent.setConnectable(false); - - graphComponent.setHorizontalScrollBar(new ThermostatScrollBar(ThermostatScrollBar.HORIZONTAL)); - graphComponent.setVerticalScrollBar(new ThermostatScrollBar(ThermostatScrollBar.VERTICAL)); - - Map<String, Object> style = graph.getStylesheet().getDefaultVertexStyle(); - style.put(mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER); - graph.getStylesheet().setDefaultVertexStyle(style); - - mxGraphLayout layout = new mxCircleLayout(graph); - layout.execute(graph.getDefaultParent()); - - layout = new mxEdgeLabelLayout(graph); - layout.execute(graph.getDefaultParent()); - - return graphComponent; - } - - @Override - public void setCheckDeadlockControlEnabled(final boolean enabled) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - SwingVmDeadLockView.this.checkForDeadlockButton.setEnabled(enabled); - } - }); - } - - private static void addDeadlockToGraph(Information info, mxGraph graph, Object parent, FontMetrics metrics) { - graph.getModel().beginUpdate(); // batch updates - try { - Map<String, Object> idToCell = new HashMap<>(); - Map<String, String> idToLabel = new HashMap<>(); - - for (DeadlockParser.Thread thread : info.threads) { - String label = getThreadLabel(thread); - String tooltip = getThreadTooltip(thread); - idToLabel.put(thread.id, label); - GraphItem node = new GraphItem(label, tooltip); - final int PADDING = 20; - int width = metrics.stringWidth(label) + PADDING; - int height = metrics.getHeight() + PADDING; - Object threadNode = graph.insertVertex(parent, thread.id, node, 0, 0, width, height); - idToCell.put(thread.id, threadNode); - } - - for (DeadlockParser.Thread thread : info.threads) { - String label = translate.localize(LocaleResources.DEADLOCK_WAITING_ON).getContents(); - String tooltip = getEdgeTooltip(thread, idToLabel); - GraphItem edge = new GraphItem(label, tooltip); - graph.insertEdge(parent, thread.waitingOn.name, edge, idToCell.get(thread.id), idToCell.get(thread.waitingOn.ownerId)); - } - - } finally { - graph.getModel().endUpdate(); - } - } - - private static String getThreadLabel(DeadlockParser.Thread thread) { - return translate.localize(LocaleResources.DEADLOCK_THREAD_NAME, thread.name, thread.id).getContents(); - } - - private static String getThreadTooltip(DeadlockParser.Thread thread) { - return translate.localize( - LocaleResources.DEADLOCK_THREAD_TOOLTIP, - StringUtils.htmlEscape(thread.waitingOn.name), - stackTraceToHtmlString(thread.stackTrace)) - .getContents(); - } - - private static String stackTraceToHtmlString(List<String> items) { - StringBuilder result = new StringBuilder(); - for (String item : items) { - result.append(StringUtils.htmlEscape(item)).append("<br/>"); - } - return result.toString(); - } - - private static String getEdgeTooltip(DeadlockParser.Thread thread, Map<String, String> idToLabel) { - return translate.localize( - LocaleResources.DEADLOCK_EDGE_TOOLTIP, - idToLabel.get(thread.id), - idToLabel.get(thread.waitingOn.ownerId)) - .getContents(); - } - - @Override - public Component getUiComponent() { - return actualComponent; - } - - static class GraphItem implements Serializable { - - private final String label; - private final String tooltip; - - public GraphItem(String label, String tooltip) { - this.label = label; - this.tooltip = tooltip; - } - - @Override - public int hashCode() { - return Objects.hash(label, tooltip); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - GraphItem other = (GraphItem) obj; - return Objects.equals(label, other.label) && Objects.equals(tooltip, other.tooltip); - } - - @Override - public String toString() { - return label; - } - - public String getTooltip() { - return tooltip; - } - } - -}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadAliveDaemonTimelinePanel.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl; - -import com.redhat.thermostat.shared.locale.Translate; -import com.redhat.thermostat.thread.client.common.locale.LocaleResources; - -import javax.swing.BoxLayout; -import javax.swing.GroupLayout; -import javax.swing.GroupLayout.Alignment; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.LayoutStyle.ComponentPlacement; -import javax.swing.SwingConstants; - -@SuppressWarnings("serial") -class ThreadAliveDaemonTimelinePanel extends JPanel { - - private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); - - private JLabel liveThreads; - private JLabel daemonThreads; - private JPanel timelinePanel; - - /** - * Create the panel. - */ - public ThreadAliveDaemonTimelinePanel() { - JPanel runningPanel = new JPanel(); - - timelinePanel = new JPanel(); - timelinePanel.setOpaque(false); - timelinePanel.setLayout(new BoxLayout(timelinePanel, BoxLayout.X_AXIS)); - - GroupLayout groupLayout = new GroupLayout(this); - groupLayout.setHorizontalGroup( - groupLayout.createParallelGroup(Alignment.TRAILING) - .addComponent(runningPanel, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 577, Short.MAX_VALUE) - .addComponent(timelinePanel, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 577, Short.MAX_VALUE) - ); - groupLayout.setVerticalGroup( - groupLayout.createParallelGroup(Alignment.LEADING) - .addGroup(groupLayout.createSequentialGroup() - .addComponent(runningPanel, GroupLayout.PREFERRED_SIZE, 41, GroupLayout.PREFERRED_SIZE) - .addPreferredGap(ComponentPlacement.RELATED) - .addComponent(timelinePanel, GroupLayout.DEFAULT_SIZE, 254, Short.MAX_VALUE)) - ); - - JLabel liveThreadsLabel = new JLabel(t.localize(LocaleResources.LIVE_THREADS).getContents() + ":"); - - JLabel daemonThreadsLabel = new JLabel(t.localize(LocaleResources.DAEMON_THREADS).getContents() + ":"); - - liveThreads = new JLabel("-"); - liveThreads.setHorizontalAlignment(SwingConstants.RIGHT); - - daemonThreads = new JLabel("-"); - daemonThreads.setHorizontalAlignment(SwingConstants.RIGHT); - GroupLayout gl_runningPanel = new GroupLayout(runningPanel); - gl_runningPanel.setHorizontalGroup( - gl_runningPanel.createParallelGroup(Alignment.LEADING) - .addGroup(gl_runningPanel.createSequentialGroup() - .addComponent(liveThreadsLabel) - .addGap(18) - .addComponent(liveThreads, GroupLayout.PREFERRED_SIZE, 85, GroupLayout.PREFERRED_SIZE) - .addGap(18) - .addComponent(daemonThreadsLabel) - .addPreferredGap(ComponentPlacement.RELATED) - .addComponent(daemonThreads, GroupLayout.PREFERRED_SIZE, 49, GroupLayout.PREFERRED_SIZE) - .addContainerGap(54, Short.MAX_VALUE)) - ); - gl_runningPanel.setVerticalGroup( - gl_runningPanel.createParallelGroup(Alignment.TRAILING) - .addGroup(Alignment.LEADING, gl_runningPanel.createSequentialGroup() - .addGroup(gl_runningPanel.createParallelGroup(Alignment.BASELINE) - .addComponent(liveThreadsLabel) - .addComponent(liveThreads) - .addComponent(daemonThreads) - .addComponent(daemonThreadsLabel)) - .addContainerGap(26, Short.MAX_VALUE)) - ); - runningPanel.setLayout(gl_runningPanel); - setLayout(groupLayout); - - } - - public JLabel getLiveThreads() { - return liveThreads; - } - - public JLabel getDaemonThreads() { - return daemonThreads; - } - - public JPanel getTimelinePanel() { - return timelinePanel; - } -} -
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadDetailsChart.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl; - -import javax.swing.BoxLayout; -import javax.swing.JPanel; - -@SuppressWarnings("serial") -public class ThreadDetailsChart extends JPanel { - - public ThreadDetailsChart() { - setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); - } -} -
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadMainPanel.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,269 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl; - -import com.redhat.thermostat.client.swing.IconResource; -import com.redhat.thermostat.client.swing.UIDefaults; -import com.redhat.thermostat.client.swing.components.ActionToggleButton; -import com.redhat.thermostat.client.swing.components.FontAwesomeIcon; -import com.redhat.thermostat.client.swing.components.HeaderPanel; -import com.redhat.thermostat.client.swing.components.Icon; -import com.redhat.thermostat.client.swing.components.OverlayPanel; -import com.redhat.thermostat.client.swing.components.ShadowLabel; -import com.redhat.thermostat.client.swing.components.ThermostatScrollPane; -import com.redhat.thermostat.client.swing.components.ThermostatThinScrollBar; -import com.redhat.thermostat.client.ui.Palette; -import com.redhat.thermostat.shared.locale.Translate; -import com.redhat.thermostat.thread.client.common.locale.LocaleResources; -import com.redhat.thermostat.thread.model.ThreadSession; - -import javax.swing.BoxLayout; -import javax.swing.DefaultListModel; -import javax.swing.GroupLayout; -import javax.swing.GroupLayout.Alignment; -import javax.swing.JList; -import javax.swing.JPanel; -import javax.swing.JSplitPane; -import javax.swing.ListCellRenderer; -import javax.swing.ListModel; -import javax.swing.ListSelectionModel; -import javax.swing.OverlayLayout; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Point; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.Date; -import java.util.List; - -@SuppressWarnings("serial") -class ThreadMainPanel extends JPanel { - - private static final Icon START_ICON = IconResource.SAMPLE.getIcon(); - private final Icon stopIcon; - - private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); - private JSplitPane splitPane; - - private ActionToggleButton toggleButton; - private ActionToggleButton showRecordedSessionsButton; - - private OverlayPanel overlay; - - private UIDefaults uiDefaults; - private ThreadSessionList sessionsPanel; - private DefaultListModel<ThreadSession> sessionsModel; - - @Override - public boolean isOptimizedDrawingEnabled() { - return false; - } - - public ThreadMainPanel(UIDefaults uiDefaults) { - this.uiDefaults = uiDefaults; - - setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); - - HeaderPanel headerPanel = new HeaderPanel(); - headerPanel.setHeader(t.localize(LocaleResources.THREAD_CONTROL_PANEL)); - - stopIcon = new FontAwesomeIcon('\uf28e', START_ICON.getIconHeight(), uiDefaults.getIconColor()); - - toggleButton = new ActionToggleButton(START_ICON, stopIcon, t.localize(LocaleResources.THREAD_MONITOR_SWITCH)); - toggleButton.setName("recordButton"); - headerPanel.addToolBarButton(toggleButton); - - Icon listSessionsIcon = IconResource.HISTORY.getIcon(); - showRecordedSessionsButton = new ActionToggleButton(listSessionsIcon, t.localize(LocaleResources.THREAD_MONITOR_DISPLAY_SESSIONS)); - showRecordedSessionsButton.setName("showRecordedSessionsButton"); - headerPanel.addToolBarButton(showRecordedSessionsButton); - - overlay = new OverlayPanel(t.localize(LocaleResources.RECORDING_LIST), true, true); - overlay.setName("threadOverlayPanel"); - overlay.addCloseEventListener(new OverlayPanel.CloseEventListener() { - @Override - public void closeRequested(OverlayPanel.CloseEvent event) { - showRecordedSessionsButton.doClick(); - } - }); - - JPanel stack = new JPanel(); - stack.setName("threadStackPanel"); - stack.setOpaque(true); - stack.setLayout(new OverlayLayout(stack)); - - splitPane = new JSplitPane(); - splitPane.setName("threadMainPanelSplitPane"); - splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); - splitPane.setOneTouchExpandable(true); - - JPanel content = new JPanel(); - GroupLayout gl_content = new GroupLayout(content); - gl_content.setHorizontalGroup( - gl_content.createParallelGroup(Alignment.TRAILING) - .addGroup(Alignment.LEADING, gl_content.createSequentialGroup() - .addContainerGap() - .addComponent(splitPane, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) - ); - gl_content.setVerticalGroup( - gl_content.createParallelGroup(Alignment.TRAILING) - .addGroup(Alignment.LEADING, gl_content.createSequentialGroup() - .addContainerGap() - .addComponent(splitPane, 0, 240, Short.MAX_VALUE) - .addContainerGap()) - ); - - content.setLayout(gl_content); - - stack.add(overlay); - stack.add(content); - stack.setOpaque(false); - - headerPanel.setContent(stack); - - add(headerPanel); - - sessionsModel = new DefaultListModel<>(); - - sessionsPanel = new ThreadSessionList(sessionsModel); - sessionsPanel.setSelectionMode(JList.VERTICAL); - sessionsPanel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - sessionsPanel.setOpaque(false); - sessionsPanel.setCellRenderer(new ThreadSessionRenderer()); - sessionsPanel.addMouseMotionListener(new MouseAdapter() { - @Override - public void mouseMoved(MouseEvent e) { - Point where = new Point(e.getX(), e.getY()); - int index = sessionsPanel.locationToIndex(where); - int hoveredIndex = sessionsPanel.getHoveredIndex(); - if (index != hoveredIndex) { - sessionsPanel.setHoveredIndex(index); - sessionsPanel.repaint(); - } - } - }); - ThermostatScrollPane scrollPane = new ThermostatScrollPane(sessionsPanel); - scrollPane.setVerticalScrollBar(new ThermostatThinScrollBar(ThermostatThinScrollBar.VERTICAL)); - overlay.add(scrollPane); - } - - public ThreadSessionList getSessionsPanel() { - return sessionsPanel; - } - - public JSplitPane getSplitPane() { - return splitPane; - } - - public ActionToggleButton getRecordingToggleButton() { - return toggleButton; - } - - public ActionToggleButton getShowRecordedSessionsButton() { - return showRecordedSessionsButton; - } - - public void toggleOverlayPanel(boolean visible) { - overlay.setOverlayVisible(visible); - } - - public class ThreadSessionRenderer implements ListCellRenderer<ThreadSession> { - - @Override - public Component getListCellRendererComponent(JList<? extends ThreadSession> list, - ThreadSession value, int index, - boolean isSelected, - boolean cellHasFocus) - { - JPanel panel = new JPanel(); - panel.setLayout(new BorderLayout()); - panel.setOpaque(false); - ShadowLabel label = new ShadowLabel(); - label.setText("[" + new Date(value.getTimeStamp()) +"]"); - label.setOpaque(false); - - if (isSelected || cellHasFocus) { - panel.setOpaque(true); - panel.setBackground((Color) uiDefaults.getSelectedComponentBGColor()); - label.setForeground((Color) uiDefaults.getSelectedComponentFGColor()); - - } else if ((sessionsPanel.getHoveredIndex() == index)) { - panel.setOpaque(true); - panel.setBackground(Palette.ELEGANT_CYAN.getColor()); - label.setForeground((Color) uiDefaults.getSelectedComponentFGColor()); - - } else { - label.setForeground((Color) uiDefaults.getComponentFGColor()); - } - - panel.add(label); - return panel; - } - } - - public void setOverlayContent(List<ThreadSession> threadSessions) { - sessionsModel.clear(); - - for (ThreadSession session : threadSessions) { - sessionsModel.addElement(session); - } - sessionsPanel.setHoveredIndex(-1); - - overlay.revalidate(); - overlay.repaint(); - - } - - public class ThreadSessionList extends JList<ThreadSession> { - private int hoveredIndex; - public ThreadSessionList(ListModel<ThreadSession> dataModel) { - super(dataModel); - hoveredIndex = -1; - } - - public int getHoveredIndex() { - return hoveredIndex; - } - - public void setHoveredIndex(int hoveredIndex) { - this.hoveredIndex = hoveredIndex; - } - } -} -
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadTable.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl; - -import javax.swing.JPanel; -import javax.swing.BoxLayout; - -@SuppressWarnings("serial") -public class ThreadTable extends JPanel { - /** - * Create the panel. - */ - public ThreadTable() { - setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); - } -} -
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/RangeComponent.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl.timeline; - -import com.redhat.thermostat.thread.client.swing.experimental.components.ContentPane; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.RangedTimelineProbe; -import java.awt.Graphics; -import java.awt.Rectangle; - -/** - * - */ -public class RangeComponent extends ContentPane { - private RangedTimelineProbe info; - - public RangeComponent(RangedTimelineProbe info) { - this.info = info; - setOpaque(false); - } - - public RangedTimelineProbe getInfo() { - return info; - } - - @Override - protected void paintComponent(Graphics g) { - g.setColor(info.getColor().getColor()); - Rectangle bounds = g.getClipBounds(); - g.fillRect(bounds.x, bounds.y, bounds.width - 1, bounds.height - 1); - } -}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/RangeComponentHeader.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,158 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl.timeline; - -import com.redhat.thermostat.client.swing.UIDefaults; -import com.redhat.thermostat.client.swing.components.FontAwesomeIcon; -import com.redhat.thermostat.client.swing.components.Icon; -import com.redhat.thermostat.shared.locale.Translate; -import com.redhat.thermostat.thread.client.common.locale.LocaleResources; -import com.redhat.thermostat.thread.client.swing.experimental.components.ContentPane; -import com.redhat.thermostat.thread.client.swing.experimental.components.DataPane; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.TimelineModel; -import java.awt.BorderLayout; -import java.awt.GridLayout; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import javax.swing.JLabel; - -/** - * - */ -public class RangeComponentHeader extends ContentPane { - - private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); - - private final TimelineModel model; - private final UIDefaults defaults; - private DataPane controls; - - private JLabel zoomOut; - private JLabel restoreZoom; - private JLabel zoomIn; - - public RangeComponentHeader(TimelineModel model, UIDefaults defaults) { - this.model = model; - this.defaults = defaults; - } - - public void initComponents() { - controls = new DataPane(); - controls.setLayout(new GridLayout(1, 0, 5, 5)); - - Icon baseIcon = new FontAwesomeIcon('\uf066', 15, defaults.getIconColor()); - Icon hoverIcon = new FontAwesomeIcon('\uf066', 15, - defaults.getSelectedComponentBGColor()); - zoomOut = new JLabel(baseIcon); - zoomOut.setToolTipText(t.localize(LocaleResources.ZOOM_OUT).getContents()); - zoomOut.addMouseListener(new Hover(zoomOut, baseIcon, hoverIcon)); - zoomOut.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - double ratio = model.getMagnificationRatio(); - model.setMagnificationRatio(ratio/2); - } - }); - controls.add(zoomOut); - - baseIcon = new FontAwesomeIcon('\uf03b', 15, defaults.getIconColor()); - hoverIcon = new FontAwesomeIcon('\uf03b', 15, - defaults.getSelectedComponentBGColor()); - restoreZoom = new JLabel(baseIcon); - restoreZoom.setToolTipText(t.localize(LocaleResources.RESTORE_ZOOM).getContents()); - restoreZoom.addMouseListener(new Hover(restoreZoom, baseIcon, hoverIcon)); - restoreZoom.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - model.setMagnificationRatio(TimelineModel.DEFAULT_RATIO); - } - }); - controls.add(restoreZoom); - - baseIcon = new FontAwesomeIcon('\uf065', 15, defaults.getIconColor()); - hoverIcon = new FontAwesomeIcon('\uf065', 15, - defaults.getSelectedComponentBGColor()); - zoomIn = new JLabel(baseIcon); - zoomIn.setToolTipText(t.localize(LocaleResources.ZOOM_IN).getContents()); - zoomIn.addMouseListener(new Hover(zoomIn, baseIcon, hoverIcon)); - zoomIn.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - double ratio = model.getMagnificationRatio(); - model.setMagnificationRatio(ratio*2); - } - }); - controls.add(zoomIn); - - add(controls, BorderLayout.EAST); - } - - public void setControlsEnabled(boolean b) { - zoomIn.setEnabled(b); - zoomOut.setEnabled(b); - restoreZoom.setEnabled(b); - } - - private class Hover extends MouseAdapter { - - private final JLabel label; - private final Icon baseIcon; - private final Icon hoverIcon; - - public Hover(JLabel label, Icon baseIcon, Icon hoverIcon) { - - this.label = label; - this.baseIcon = baseIcon; - this.hoverIcon = hoverIcon; - } - - @Override - public void mouseEntered(MouseEvent e) { - onMouseHover(true); - } - - @Override - public void mouseExited(MouseEvent e) { - onMouseHover(false); - } - - public void onMouseHover(boolean hover) { - label.setIcon(hover ? hoverIcon : baseIcon); - repaint(); - } - } -}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/RangeComponentLayoutManager.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl.timeline; - -import com.redhat.thermostat.client.swing.components.AbstractLayout; -import com.redhat.thermostat.common.model.LongRangeNormalizer; -import com.redhat.thermostat.common.model.Range; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.RangedTimelineProbe; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.TimelineModel; -import java.awt.Container; -import java.awt.Dimension; - -/** - * - */ -class RangeComponentLayoutManager extends AbstractLayout { - - private static final int STATE_COMPONENT_HEIGHT = 5; - - private static final boolean DEBUG_TIMELINES = false; - - @Override - protected void doLayout(Container parent) { - TimelineContainer container = (TimelineContainer) parent; - - Dimension size = getRealLayoutSize(container); - TimelineModel model = container.getModel(); - - LongRangeNormalizer normalizer = new LongRangeNormalizer(model.getRange()); - - normalizer.setMinNormalized(0); - normalizer.setMaxNormalized(size.width); - - if (DEBUG_TIMELINES) System.err.print(container.getName()); - - for (RangeComponent rangeComponent : container) { - - RangedTimelineProbe info = rangeComponent.getInfo(); - Range<Long> range = info.getRange(); - int x = (int) normalizer.getValueNormalized(range.getMin()); - int width = (int) normalizer.getValueNormalized(range.getMax()) - x + 1; - - rangeComponent.setBounds(x, 0, width, 5); - - if (DEBUG_TIMELINES) System.err.print(" [" + range.getMin() + - " - " + range.getMax() + "]"); - } - - if (DEBUG_TIMELINES) System.err.println(""); - } - - @Override - public Dimension preferredLayoutSize(Container parent) { - return getRealLayoutSize(parent); - } - - public Dimension getRealLayoutSize(Container parent) { - TimelineContainer container = (TimelineContainer) parent; - - TimelineModel model = container.getModel(); - - Range<Long> range = model.getRange(); - - double length = range.getMax() - range.getMin(); - double multiplier = model.getMagnificationRatio(); - - return new Dimension((int) Math.round(length * multiplier), - STATE_COMPONENT_HEIGHT); - } -}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/RulerComponent.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,164 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl.timeline; - -import com.redhat.thermostat.client.swing.GraphicsUtils; -import com.redhat.thermostat.client.swing.UIDefaults; -import com.redhat.thermostat.client.ui.Palette; -import com.redhat.thermostat.thread.client.swing.experimental.components.DataPane; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.TimelineModel; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Rectangle; - -/** - * - */ -public class RulerComponent extends DataPane { - - protected class RenderingInfo { - long startRendering; - long stopRendering; - - long startMark; - long increment; - } - - protected final UIDefaults uiDefaults; - protected TimelineModel model; - private boolean selected; - - public RulerComponent(UIDefaults defaults, TimelineModel model) { - - super(Palette.LIGHT_GRAY, Palette.WHITE); - - this.uiDefaults = defaults; - this.model = model; - setFont(defaults.getDefaultFont().deriveFont(Font.PLAIN, 10.f)); - setName("ruler"); - } - - public boolean isSelected() { - return selected; - } - - public void setSelected(boolean selected) { - this.selected = selected; - } - - @Override - public Dimension getPreferredSize() { - Dimension pref = super.getPreferredSize(); - pref.height = getHeight(); - return pref; - } - - @Override - public Dimension getMinimumSize() { - return getPreferredSize(); - } - - @Override - public Dimension getSize() { - return getPreferredSize(); - } - - private RenderingInfo getRenderingInfo(Rectangle bounds) { - - RenderingInfo info = new RenderingInfo(); - info.stopRendering = bounds.x + bounds.width; - info.increment = 10; - - long start = model.getRange().getMin(); - long visibleStartTime = start + model.getScrollBarModel().getValue(); - - // small mark, 1 second boundary - long mark = visibleStartTime - (1_000 * (visibleStartTime/1_000)); - info.startRendering = -mark; - - return info; - } - - @Override - protected void paintComponent(Graphics g) { - Graphics2D graphics = GraphicsUtils.getInstance().createAAGraphics(g); - - Rectangle bounds = graphics.getClipBounds(); - if (!isSelected()) { - super.paintComponent(g); - } else { - graphics.setPaint(uiDefaults.getSelectedComponentBGColor()); - graphics.fillRect(bounds.x, bounds.y, bounds.width, bounds.height); - } - - Color lines = Palette.PALE_GRAY.getColor(); - Color tickLines = Palette.DARK_GRAY.getColor(); - - RenderingInfo info = getRenderingInfo(bounds); - int height = bounds.y + bounds.height; - - boolean resetColor = false; - long mark = 10l; - - graphics.setColor(lines); - for (int i = (int) info.startRendering, j = (int) info.startMark; - i < info.stopRendering; i += info.increment, j++) - { - if (j % mark == 0) { - graphics.setColor(tickLines); - resetColor = true; - } - - graphics.drawLine(i, bounds.y, i, height); - - if (resetColor) { - graphics.setColor(lines); - resetColor = false; - } - } - - // TODO -// if (drawLabels) { -// drawLabels(graphics, info); -// } - - graphics.dispose(); - } -}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/TimelineAdjustmentListener.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl.timeline; - -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.TimelineModel; -import java.awt.event.AdjustmentEvent; -import java.awt.event.AdjustmentListener; -import javax.swing.BoundedRangeModel; - -/** - * - */ -public class TimelineAdjustmentListener implements AdjustmentListener { - - private TimelineModel model; - private boolean followMode; - - public TimelineAdjustmentListener(TimelineModel model) { - this.model = model; - } - - @Override - public void adjustmentValueChanged(AdjustmentEvent e) { - BoundedRangeModel scrollBarModel = model.getScrollBarModel(); - if (scrollBarModel.getValueIsAdjusting()) { - followMode = false; - return; - } - - int max = scrollBarModel.getMaximum(); - int currentExtent = scrollBarModel.getValue() + - scrollBarModel.getExtent(); - - if (currentExtent == max) { - followMode = true; - } - - if (followMode) { - int value = max - scrollBarModel.getExtent(); - scrollBarModel.setValue(value); - } - } -}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/TimelineComponent.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl.timeline; - -import com.redhat.thermostat.client.swing.UIDefaults; -import com.redhat.thermostat.client.swing.components.ThermostatScrollPane; -import com.redhat.thermostat.thread.client.common.model.timeline.ThreadInfo; -import com.redhat.thermostat.thread.client.swing.experimental.components.ContentPane; -import com.redhat.thermostat.thread.client.swing.experimental.components.Separator; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.TimelineModel; -import java.awt.BorderLayout; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -/** - * - */ -public class TimelineComponent extends RulerComponent { - - private static final int MIN_HEIGHT = 50; - private final ThreadInfo threadInfo; - - private ContentPane labelPane; - - private TimelineLabel label; - - private ThermostatScrollPane scrollPane; - private TimelineContainer timelineContainer; - - public TimelineComponent(UIDefaults uiDefaults, ThreadInfo threadInfo, - TimelineModel model) - { - super(uiDefaults, model); - this.threadInfo = threadInfo; - } - - public void initComponents() { - setName(threadInfo.getName()); - - initModel(); - - initLabelPane(); - initThreadPane(); - - setBorder(new Separator(uiDefaults, Separator.Side.BOTTOM, - Separator.Type.SOLID)); - - Hover hover = new Hover(); - addMouseListener(hover); - } - - private void initModel() { - model.getScrollBarModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - repaint(); - } - }); - } - - private void initThreadPane() { - - timelineContainer = new TimelineContainer(model); - timelineContainer.setName(threadInfo.getName()); - - scrollPane = new ThermostatScrollPane(timelineContainer); - scrollPane.setHorizontalScrollBarPolicy(ThermostatScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - scrollPane.setVerticalScrollBarPolicy(ThermostatScrollPane.VERTICAL_SCROLLBAR_NEVER); - - add(scrollPane, BorderLayout.CENTER); - - scrollPane.getHorizontalScrollBar().setModel(model.getScrollBarModel()); - } - - public TimelineContainer getTimelineContainer() { - return timelineContainer; - } - - private void initLabelPane() { - label = new TimelineLabel(uiDefaults, getName()); - labelPane = new ContentPane(); - - labelPane.setOpaque(false); - labelPane.setLayout(new GridBagLayout()); - - GridBagConstraints gbc = new GridBagConstraints(); - gbc.anchor = GridBagConstraints.WEST; - gbc.fill = GridBagConstraints.NONE; - gbc.weightx = 1.f; - - labelPane.add(label, gbc); - add(labelPane, BorderLayout.NORTH); - } - - @Override - public int getHeight() { - return MIN_HEIGHT; - } - - private class Hover extends MouseAdapter { - @Override - public void mouseEntered(MouseEvent e) { - onMouseHover(true); - } - - @Override - public void mouseExited(MouseEvent e) { - onMouseHover(false); - } - - public void onMouseHover(boolean hover) { - label.onMouseHover(hover); - repaint(); - } - } -}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/TimelineContainer.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl.timeline; - -import com.redhat.thermostat.thread.client.swing.experimental.components.ContentPane; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.RangeChangeEvent; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.RangeChangeListener; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.RatioChangeEvent; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.RatioChangeListener; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.TimelineModel; -import java.awt.Component; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -/** - * - */ -public class TimelineContainer extends ContentPane implements Iterable<RangeComponent> { - - private List<RangeComponent> rangeComponents; - private TimelineModel model; - - public TimelineContainer(TimelineModel model) { - rangeComponents = new ArrayList<>(); - - setOpaque(false); - setLayout(new RangeComponentLayoutManager()); - - setModel(model); - } - - public Component add(RangeComponent comp) { - rangeComponents.add(comp); - return super.add(comp); - } - - @Override - public Iterator<RangeComponent> iterator() { - return rangeComponents.iterator(); - } - - public TimelineModel getModel() { - return model; - } - - public void setModel(TimelineModel model) { - this.model = model; - model.addRangeChangeListener(new RangeChangeListener() { - @Override - public void rangeChanged(RangeChangeEvent event) { - revalidate(); - repaint(); - } - }); - model.addRatioChangeListener(new RatioChangeListener() { - @Override - public void ratioChanged(RatioChangeEvent event) { - revalidate(); - repaint(); - } - }); - } - - public RangeComponent getLastRangeComponent() { - return rangeComponents.isEmpty() ? null : - rangeComponents.get(rangeComponents.size() - 1); - } -}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/TimelineLabel.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl.timeline; - -import com.redhat.thermostat.client.swing.UIDefaults; -import com.redhat.thermostat.client.swing.components.Icon; -import com.redhat.thermostat.client.swing.components.LabelField; -import com.redhat.thermostat.client.ui.Palette; -import com.redhat.thermostat.shared.locale.LocalizedString; -import com.redhat.thermostat.thread.client.swing.experimental.components.DataPane; -import com.redhat.thermostat.thread.client.swing.experimental.components.Separator; -import java.awt.Color; -import javax.swing.SwingConstants; -import javax.swing.border.EmptyBorder; - -/** - * - */ -class TimelineLabel extends DataPane { - private LabelField nameLabel; - private Icon infoOn; - private Icon infoOff; - - TimelineLabel(UIDefaults defaults, String text) { - super(Palette.WHITE, Palette.LIGHT_GRAY); - - setBorder(new Separator(defaults, Separator.Side.BOTTOM, Separator.Type.SOLID)); - - nameLabel = new LabelField(LocalizedString.EMPTY_STRING); - nameLabel.setFont(defaults.getDefaultFont().deriveFont(10.f)); - - nameLabel.setText(text); - nameLabel.setHorizontalAlignment(SwingConstants.CENTER); - nameLabel.setVerticalAlignment(SwingConstants.CENTER); - nameLabel.setForeground((Color) defaults.getSelectedComponentBGColor()); - - // make same small space around the label, a bit higher left and right - // to account for the missing icon - nameLabel.setBorder(new EmptyBorder(2, 4, 2, 4)); - - nameLabel.setHorizontalTextPosition(SwingConstants.LEFT); - - // FIXME && TODO: comment this out for now, the functionality this is - // meant for is not yet implemented in the controller -// infoOn = new FontAwesomeIcon('\uf05a', 12, Palette.DARK_GRAY.getColor()); -// infoOff = new FontAwesomeIcon('\uf05a', 12, Palette.PALE_GRAY.getColor()); -// -// nameLabel.setIcon(infoOff); - - add(nameLabel); - } - - public void onMouseHover(boolean hover) { -// nameLabel.setIcon(hover ? infoOn : infoOff); - repaint(); - } -}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/TimelineViewComponent.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,152 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl.timeline; - -import com.redhat.thermostat.client.swing.UIDefaults; -import com.redhat.thermostat.client.swing.components.ThermostatScrollBar; -import com.redhat.thermostat.client.swing.components.ThermostatScrollPane; -import com.redhat.thermostat.common.model.Range; -import com.redhat.thermostat.thread.client.swing.experimental.components.ContentPane; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.LegendPanel; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.RangeChangeEvent; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.RangeChangeListener; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.RatioChangeEvent; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.RatioChangeListener; -import com.redhat.thermostat.thread.client.swing.impl.timeline.model.TimelineModel; -import java.awt.BorderLayout; -import java.awt.Rectangle; - -/** - * - */ -public class TimelineViewComponent extends ContentPane { - - private TimelineModel model; - private ThermostatScrollPane scrollPane; - private TimelineViewport viewport; - - private ThermostatScrollBar scrollBar; - private UIDefaults uiDefaults; - private RangeComponentHeader header; - - public TimelineViewComponent(UIDefaults uiDefaults) { - this.uiDefaults = uiDefaults; - } - - public void initComponents() { - - ContentPane contentPane = new ContentPane(); - - this.model = new TimelineModel(); - - viewport = new TimelineViewport(); - - scrollPane = new ThermostatScrollPane(viewport); - scrollPane.setVerticalScrollBarPolicy(ThermostatScrollPane.VERTICAL_SCROLLBAR_ALWAYS); - scrollPane.setHorizontalScrollBarPolicy(ThermostatScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - - header = new RangeComponentHeader(model, uiDefaults); - header.initComponents(); - scrollPane.setColumnHeaderView(header); - - contentPane.add(scrollPane, BorderLayout.CENTER); - - scrollBar = new ThermostatScrollBar(ThermostatScrollBar.HORIZONTAL); - model.setScrollBarModel(scrollBar.getModel()); - - scrollBar.addAdjustmentListener(new TimelineAdjustmentListener(model)); - - contentPane.add(scrollBar, BorderLayout.SOUTH); - scrollBar.setEnabled(false); - scrollBar.setVisible(false); - - header.setControlsEnabled(false); - - add(contentPane, BorderLayout.CENTER); - - LegendPanel legend = new LegendPanel(uiDefaults); - add(legend, BorderLayout.SOUTH); - - model.addRatioChangeListener(new RatioChangeListener() { - @Override - public void ratioChanged(RatioChangeEvent event) { - checkEnableScrollbar(); - } - }); - model.addRangeChangeListener(new RangeChangeListener() { - @Override - public void rangeChanged(RangeChangeEvent event) { - checkEnableScrollbar(); - } - }); - } - - private void checkEnableScrollbar() { - Range<Long> range = model.getRange(); - // no data, so no scrolling - if (range == null) { - scrollBar.setVisible(false); - scrollBar.setEnabled(false); - return; - } - - Rectangle bounds = getBounds(); - long length = bounds.x + bounds.width; - length = Math.round(length / model.getMagnificationRatio()); - - long lengthInMs = range.getMax() - range.getMin(); - lengthInMs = Math.round(lengthInMs / model.getMagnificationRatio()); - - boolean shouldEnable = (length < lengthInMs); - - scrollBar.setVisible(shouldEnable); - scrollBar.setEnabled(shouldEnable); - } - - public void addTimeline(TimelineComponent timeline) { - viewport.add(timeline); - header.setControlsEnabled(true); - checkEnableScrollbar(); - revalidate(); - repaint(); - } - - public TimelineModel getModel() { - return model; - } -} -
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/TimelineViewport.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl.timeline; - -import com.redhat.thermostat.thread.client.swing.experimental.components.ContentPane; -import java.awt.Dimension; -import java.awt.Rectangle; -import javax.swing.BoxLayout; -import javax.swing.Scrollable; - -/** - * - */ -public class TimelineViewport extends ContentPane implements Scrollable { - - public TimelineViewport() { - setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - } - - @Override - public Dimension getPreferredScrollableViewportSize() { - return getPreferredSize(); - } - - @Override - public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { - return 1; - } - - @Override - public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { - return 1; - } - - @Override - public boolean getScrollableTracksViewportWidth() { - return true; - } - - @Override - public boolean getScrollableTracksViewportHeight() { - return false; - } -}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/model/LegendPanel.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl.timeline.model; - -import com.redhat.thermostat.client.swing.GraphicsUtils; -import com.redhat.thermostat.client.swing.UIDefaults; -import com.redhat.thermostat.thread.client.common.chart.ChartColors; -import com.redhat.thermostat.thread.client.swing.experimental.components.DataPane; -import com.redhat.thermostat.thread.client.swing.experimental.components.Separator; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.Graphics; -import java.awt.Graphics2D; -import javax.swing.Icon; -import javax.swing.JLabel; -import javax.swing.SwingConstants; - -/** - * - */ -public class LegendPanel extends DataPane { - - public LegendPanel(UIDefaults defaults) { - setBorder(new Separator(defaults, Separator.Side.TOP.TOP, Separator.Type.SOLID)); - setLayout(new FlowLayout(FlowLayout.RIGHT, 10, 6)); - setPreferredSize(new Dimension(getWidth(), 30)); - - for (Thread.State state : Thread.State.values()) { - - Color color = ChartColors.getColor(state); - // no chart is black, it's just the default colour - if (!color.equals(Color.BLACK)) { - JLabel label = new JLabel(new ColorIcon(color), SwingConstants.LEFT); - label.setText(state.toString()); - add(label); - } - } - } - - private class ColorIcon implements Icon { - - private Color color; - private ColorIcon(Color color) { - this.color = color; - } - - @Override - public int getIconHeight() { - return 12; - } - - @Override - public int getIconWidth() { - return 12; - } - - @Override - public void paintIcon(Component c, Graphics g, int x, int y) { - Graphics2D graphics = GraphicsUtils.getInstance().createAAGraphics(g); - graphics.setColor(color); - graphics.fillRect(x, y, getIconWidth(), getIconHeight()); - graphics.dispose(); - } - } -}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/model/RangeChangeEvent.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl.timeline.model; - -import com.redhat.thermostat.common.model.Range; -import java.util.EventObject; - -/** - * - */ -public class RangeChangeEvent extends EventObject { - - private final TimelineModel source; - private final Range<Long> range; - - public RangeChangeEvent(TimelineModel source, Range<Long> range) { - super(source); - this.source = source; - this.range = range; - } - - @Override - public TimelineModel getSource() { - return (TimelineModel) super.getSource(); - } - - public Range<Long> getRange() { - return range; - } -}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/model/RangeChangeListener.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl.timeline.model; - -import java.util.EventListener; - -/** - * - */ -public interface RangeChangeListener extends EventListener { - - public void rangeChanged(RangeChangeEvent event); -}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/model/RangedTimelineProbe.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl.timeline.model; - -import com.redhat.thermostat.common.model.Range; -import com.redhat.thermostat.thread.client.common.model.timeline.TimelineProbe; - -/** - * - */ -public class RangedTimelineProbe extends TimelineProbe { - - private long probeEnd; - - public RangedTimelineProbe(TimelineProbe probe, long probeStop) - { - super(probe.getColor(), probe.getState(), probe.getTimeStamp()); - this.probeEnd = probeStop; - } - - public void setProbeEnd(long probeEnd) { - this.probeEnd = probeEnd; - } - - public Range<Long> getRange() { - return new Range<>(getTimeStamp(), probeEnd); - } -}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/model/RatioChangeEvent.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl.timeline.model; - -import java.util.EventObject; - -/** - * - */ -public class RatioChangeEvent extends EventObject { - private final TimelineModel source; - private final double ratio; - - public RatioChangeEvent(TimelineModel source, double ratio) { - super(source); - this.source = source; - this.ratio = ratio; - } - - @Override - public TimelineModel getSource() { - return (TimelineModel) super.getSource(); - } - - public double getRatio() { - return ratio; - } -}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/model/RatioChangeListener.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl.timeline.model; - -import java.util.EventListener; - -/** - * - */ -public interface RatioChangeListener extends EventListener { - public void ratioChanged(RatioChangeEvent event); -}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/model/TimelineDateFormatter.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl.timeline.model; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; - -/** - * - */ -public class TimelineDateFormatter { - private static final DateFormat DATE_FORMAT = new SimpleDateFormat("HH:mm:ss.SSS"); - - public static String format(long timeStamp) { - return DATE_FORMAT.format(new Date(timeStamp)); - } -}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/model/TimelineModel.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,129 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl.timeline.model; - -import com.redhat.thermostat.common.model.Range; -import javax.swing.BoundedRangeModel; -import javax.swing.event.EventListenerList; - -/** - * - */ -public class TimelineModel { - - public static final double DEFAULT_RATIO = 1./100.; - - private EventListenerList listenerList; - - private double magnificationRatio; - - private Range<Long> range; - private BoundedRangeModel scrollBarModel; - - private TimelineModel model; - - public TimelineModel() { - this.listenerList = new EventListenerList(); - magnificationRatio = DEFAULT_RATIO; - } - - public Range<Long> getRange() { - return range; - } - - public void setRange(Range<Long> range) { - this.range = range; - fireRangeChangeEvent(); - } - - public void setScrollBarModel(BoundedRangeModel scrollBarModel) { - this.scrollBarModel = scrollBarModel; - } - - public BoundedRangeModel getScrollBarModel() { - return scrollBarModel; - } - - public void addRangeChangeListener(RangeChangeListener listener) { - listenerList.add(RangeChangeListener.class, listener); - } - - public void addRatioChangeListener(RatioChangeListener listener) { - listenerList.add(RatioChangeListener.class, listener); - } - - public void removeRatioChangeListener(RatioChangeListener listener) { - listenerList.remove(RatioChangeListener.class, listener); - } - - public void removeRangeChangeListener(RangeChangeListener listener) { - listenerList.remove(RangeChangeListener.class, listener); - } - - public double getMagnificationRatio() { - return magnificationRatio; - } - - public void setMagnificationRatio(double magnificationRatio) { - this.magnificationRatio = magnificationRatio; - fireRatioChangeEvent(); - } - - private void fireRatioChangeEvent() { - Object[] listeners = listenerList.getListenerList(); - RatioChangeEvent event = - new RatioChangeEvent(this, magnificationRatio); - for (int i = listeners.length - 2; i >= 0; i -= 2) { - if (listeners[i] == RatioChangeListener.class) { - ((RatioChangeListener) listeners[i + 1]).ratioChanged(event); - } - } - } - - private void fireRangeChangeEvent() { - Object[] listeners = listenerList.getListenerList(); - RangeChangeEvent event = - new RangeChangeEvent(this, - new Range<>(range.getMin(), - range.getMax())); - for (int i = listeners.length - 2; i >= 0; i -= 2) { - if (listeners[i] == RangeChangeListener.class) { - ((RangeChangeListener) listeners[i + 1]).rangeChanged(event); - } - } - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/SwingLockView.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,145 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal; + +import java.awt.BorderLayout; +import java.awt.Component; + +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.table.DefaultTableModel; + +import com.redhat.thermostat.client.swing.NonEditableTableModel; +import com.redhat.thermostat.client.swing.SwingComponent; +import com.redhat.thermostat.client.swing.components.ThermostatScrollPane; +import com.redhat.thermostat.client.swing.components.ThermostatTable; +import com.redhat.thermostat.client.swing.experimental.ComponentVisibilityNotifier; +import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.thread.client.common.locale.LocaleResources; +import com.redhat.thermostat.thread.client.common.view.LockView; +import com.redhat.thermostat.thread.model.LockInfo; + +public class SwingLockView extends LockView implements SwingComponent { + + protected static final String TABLE_NAME = "locks-table"; + + private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + + private static final int VALUE_COLUMN = 1; + + private JPanel topPanel; + private ThermostatTable table; + private DefaultTableModel model; + + public SwingLockView() { + topPanel = new JPanel(); + topPanel.setLayout(new BorderLayout()); + + model = new NonEditableTableModel(18, 2); + Object[][] dataVector = new Object[][] { + new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_CONTENDED_LOCK_ATTEMPS).getContents(), 0 }, + new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_DEFLATIONS).getContents(), 0 }, + new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_EMPTY_NOTIFICATIONS).getContents(), 0 }, + new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_FAILED_SPINS).getContents(), 0 }, + new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_FUTILE_WAKEUPS).getContents(), 0 }, + new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_INFLATIONS).getContents(), 0 }, + new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_MON_EXTANT).getContents(), 0 }, + new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_MON_IN_CIRCULATION).getContents(), 0 }, + new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_MON_SCAVENGED).getContents(), 0 }, + new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_NOTIFICATIONS).getContents(), 0 }, + new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_PARKS).getContents(), 0 }, + new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_PRIVATE_A).getContents(), 0 }, + new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_PRIVATE_B).getContents(), 0 }, + new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_SLOW_ENTER).getContents(), 0 }, + new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_SLOW_EXIT).getContents(), 0 }, + new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_SLOW_NOTIFY).getContents(), 0 }, + new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_SLOW_NOTIFY_ALL).getContents(), 0 }, + new Object[] { translator.localize(LocaleResources.LOCK_DESCRIPTION_SUCCESSFUL_SPINS).getContents(), 0 }, + }; + + Object[] columnIdentifiers = new Object[] { + translator.localize(LocaleResources.LOCK_COLUMN_NAME).getContents(), + translator.localize(LocaleResources.LOCK_COLUMN_VALUE).getContents()}; + model.setDataVector(dataVector, columnIdentifiers); + + table = new ThermostatTable(model); + table.setName(TABLE_NAME); + + ThermostatScrollPane scrollPane = new ThermostatScrollPane(table); + topPanel.add(scrollPane, BorderLayout.CENTER); + + new ComponentVisibilityNotifier().initialize(topPanel, notifier); + } + + @Override + public void setLatestLockData(final LockInfo data) { + SwingUtilities.invokeLater(new Runnable() { + private int row = 0; + @Override + public void run() { + updateModel(data.getContendedLockAttempts()); + updateModel(data.getDeflations()); + updateModel(data.getEmptyNotifications()); + updateModel(data.getFailedSpins()); + updateModel(data.getFutileWakeups()); + updateModel(data.getInflations()); + updateModel(data.getMonExtant()); + updateModel(data.getMonInCirculation()); + updateModel(data.getMonScavenged()); + updateModel(data.getNotifications()); + updateModel(data.getParks()); + updateModel(data.getPrivateA()); + updateModel(data.getPrivateB()); + updateModel(data.getSlowEnter()); + updateModel(data.getSlowExit()); + updateModel(data.getSlowNotify()); + updateModel(data.getSlowNotifyAll()); + updateModel(data.getSuccessfulSpins()); + } + + private void updateModel(long number) { + model.setValueAt(number, row, VALUE_COLUMN); + row++; + } + }); + } + @Override + public Component getUiComponent() { + return topPanel; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/SwingThreadCountView.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,125 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal; + +import com.redhat.thermostat.client.swing.ComponentVisibleListener; +import com.redhat.thermostat.client.swing.SwingComponent; +import com.redhat.thermostat.client.swing.components.ChartPanel; +import com.redhat.thermostat.thread.client.common.chart.LivingDaemonThreadDifferenceChart; +import com.redhat.thermostat.thread.client.common.view.ThreadCountView; + +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; +import java.awt.Component; + +public class SwingThreadCountView extends ThreadCountView implements SwingComponent { + + private ThreadAliveDaemonTimelinePanel timelinePanel; + + public SwingThreadCountView() { + timelinePanel = new ThreadAliveDaemonTimelinePanel(); + timelinePanel.addHierarchyListener(new ComponentVisibleListener() { + @Override + public void componentShown(Component component) { + SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { + @Override + protected Void doInBackground() throws Exception { + SwingThreadCountView.this.notify(Action.VISIBLE); + return null; + } + }; + worker.execute(); + } + + @Override + public void componentHidden(Component component) { + SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { + @Override + protected Void doInBackground() throws Exception { + SwingThreadCountView.this.notify(Action.HIDDEN); + return null; + } + }; + worker.execute(); + } + }); + } + + public void setLiveThreads(final String liveThreads) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + timelinePanel.getLiveThreads().setText(liveThreads); + } + }); + }; + + @Override + public void updateLivingDaemonTimeline(final LivingDaemonThreadDifferenceChart model) + { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + JPanel pane = timelinePanel.getTimelinePanel(); + pane.removeAll(); + + ChartPanel charts = new ChartPanel(model.createChart(pane.getWidth(), pane.getBackground())); + charts.setName("threadChartPanel"); + pane.add(charts); + pane.revalidate(); + pane.repaint(); + } + }); + } + + @Override + public void setDaemonThreads(final String daemonThreads) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + timelinePanel.getDaemonThreads().setText(daemonThreads); + } + }); + } + + @Override + public Component getUiComponent() { + return timelinePanel; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/SwingThreadDetailsView.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,86 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal; + +import java.awt.BorderLayout; +import java.awt.Component; + +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import com.redhat.thermostat.client.swing.SwingComponent; +import com.redhat.thermostat.client.swing.components.ChartPanel; +import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.thread.client.common.ThreadTableBean; +import com.redhat.thermostat.thread.client.common.chart.ThreadDeatailsPieChart; +import com.redhat.thermostat.thread.client.common.locale.LocaleResources; +import com.redhat.thermostat.thread.client.common.view.ThreadDetailsView; + +public class SwingThreadDetailsView extends ThreadDetailsView implements SwingComponent { + + private JPanel details; + private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); + + SwingThreadDetailsView() { + details = new JPanel(); + details.setLayout(new BorderLayout(0, 0)); + + JLabel lblNewLabel = new JLabel(t.localize(LocaleResources.THREAD_DETAILS_EMTPY).getContents()); + lblNewLabel.setIcon(new ImageIcon(getEmptyDetailsIcon().getData().array())); + details.add(lblNewLabel); + } + + @Override + public Component getUiComponent() { + return details; + } + + @Override + public void setDetails(ThreadTableBean thread) { + details.removeAll(); + + ThreadDetailsChart threadChart = new ThreadDetailsChart(); + + ChartPanel threadSummary = new ChartPanel(new ThreadDeatailsPieChart(thread).createChart()); + threadChart.add(threadSummary); + + details.add(threadChart); + details.repaint(); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/SwingThreadTableView.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,308 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal; + +import com.redhat.thermostat.client.swing.NonEditableTableModel; +import com.redhat.thermostat.client.swing.SwingComponent; +import com.redhat.thermostat.client.swing.components.ThermostatTable; +import com.redhat.thermostat.client.swing.experimental.ComponentVisibilityNotifier; +import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.thread.client.common.ThreadTableBean; +import com.redhat.thermostat.thread.client.common.locale.LocaleResources; +import com.redhat.thermostat.thread.client.common.view.ThreadTableView; + +import java.awt.Component; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; + +public class SwingThreadTableView extends ThreadTableView implements SwingComponent { + + private boolean tableRepacked = false; + + private int currentSelection = -1; + + private ThermostatTable table; + private ThreadTable tablePanel; + + private Map<ThreadTableBean, Integer> beans; + + private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); + + public SwingThreadTableView() { + + beans = new HashMap<>(); + tablePanel = new ThreadTable(); + new ComponentVisibilityNotifier().initialize(tablePanel, notifier); + + table = new ThermostatTable(new ThreadViewTableModel()); + table.setName("threadBeansTable"); + table.getModel().addTableModelListener(new TableModelListener() { + @Override + public void tableChanged(TableModelEvent e) { + // NOTE: The fireTableDataChanged executes this listener + // before the internal listener, this means this update will + // be overridden since the default listener resets the model. + // So, although we are in the EDT, we need to ensure that + // we schedule this operation for later, rather than do it + // right away... isn't Swing fun? + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (currentSelection != -1) { + table.setRowSelectionInterval(currentSelection, currentSelection); + } + } + }); + } + }); + tablePanel.add(table.wrap()); + + table.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + ThreadViewTableModel model = (ThreadViewTableModel) table.getModel(); + int selectedRow = table.getSelectedRow(); + if (selectedRow != -1) { + selectedRow = table.convertRowIndexToModel(selectedRow); + final ThreadTableBean bean = model.infos.get(selectedRow); + SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { + protected Void doInBackground() throws Exception { + threadTableNotifier.fireAction(ThreadSelectionAction.SHOW_THREAD_DETAILS, bean); + return null; + } + }; + worker.execute(); + } + } + } + }); + } + + @Override + public void clear() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + ThreadViewTableModel model = (ThreadViewTableModel) table.getModel(); + model.setRowCount(0); + beans.clear(); + } + }); + } + + @Override + public Component getUiComponent() { + return tablePanel; + } + + @Override + public void display(final ThreadTableBean tableBean) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + + // reset the selection for the next iteration + // everything is happening in one thread, so there's no fear + currentSelection = -1; + + ThreadViewTableModel model = (ThreadViewTableModel) table.getModel(); + int selectedRow = table.getSelectedRow(); + + ThreadTableBean info = null; + if (selectedRow != -1) { + info = model.infos.get(selectedRow); + } + + // update the infos + Integer beanIndex = beans.get(tableBean); + if (beanIndex == null) { + beanIndex = Integer.valueOf(model.infos.size()); + beans.put(tableBean, beanIndex); + model.infos.add(tableBean); + } + + if (info != null) { + int index = 0; + for (ThreadTableBean inModel : model.infos) { + if (info.equals(inModel)) { + currentSelection = index; + break; + } + index++; + } + } + + // just repack once, or the user will see the table moving around + if (!tableRepacked) { + table.repackCells(); + tableRepacked = true; + } + } + }); + } + + @Override + public void submitChanges() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + ThreadViewTableModel model = + (ThreadViewTableModel) table.getModel(); + model.fireTableDataChanged(); + } + }); + } + + @SuppressWarnings("serial") + private class ThreadViewTableModel extends NonEditableTableModel { + + private String [] columns = { + t.localize(LocaleResources.NAME).getContents(), + t.localize(LocaleResources.ID).getContents(), + t.localize(LocaleResources.FIRST_SEEN).getContents(), + t.localize(LocaleResources.LAST_SEEN).getContents(), + t.localize(LocaleResources.WAIT_COUNT).getContents(), + t.localize(LocaleResources.BLOCK_COUNT).getContents(), + t.localize(LocaleResources.RUNNING).getContents(), + t.localize(LocaleResources.WAITING).getContents(), + t.localize(LocaleResources.SLEEPING).getContents(), + t.localize(LocaleResources.MONITOR).getContents(), //, "Heap", "CPU Time", "User CPU Time" + }; + + private List<ThreadTableBean> infos; + public ThreadViewTableModel() { + this.infos = new ArrayList<>(); + } + + @Override + public String getColumnName(int column) { + return columns[column]; + } + + @Override + public int getColumnCount() { + return columns.length; + } + + @Override + public int getRowCount() { + if (infos == null) { + return 0; + } + return infos.size(); + } + + @Override + public Class<?> getColumnClass(int column) { + switch (column) { + case 0: + case 2: + case 3: + case 6: + case 7: + case 8: + case 9: + return String.class; + default: + return Long.class; + } + } + + @Override + public Object getValueAt(int row, int column) { + + DecimalFormat format = new DecimalFormat("###.00"); + + Object result = null; + + ThreadTableBean info = infos.get(row); + switch (column) { + case 0: + result = info.getName(); + break; + case 1: + result = info.getId(); + break; + case 2: + result = new Date(info.getStartTimeStamp()).toString(); + break; + case 3: + if (info.getStopTimeStamp() != 0) { + result = new Date(info.getStopTimeStamp()).toString(); + } else { + result = "-"; + } + break; + case 4: + result = info.getWaitedCount(); + break; + case 5: + result = info.getBlockedCount(); + break; + case 6: + result = format.format(info.getRunningPercent()); + break; + case 7: + result = format.format(info.getWaitingPercent()); + break; + case 8: + result = format.format(info.getSleepingPercent()); + break; + case 9: + result = format.format(info.getMonitorPercent()); + break; + default: + result = "n/a"; + break; + } + return result; + } + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/SwingThreadTimelineView.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,168 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal; + +import com.redhat.thermostat.client.swing.SwingComponent; +import com.redhat.thermostat.client.swing.UIDefaults; +import com.redhat.thermostat.client.swing.experimental.ComponentVisibilityNotifier; +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.thread.client.common.model.timeline.ThreadInfo; +import com.redhat.thermostat.thread.client.common.model.timeline.TimelineProbe; +import com.redhat.thermostat.thread.client.common.view.ThreadTimelineView; +import com.redhat.thermostat.thread.client.swing.experimental.utils.EDTHelper; +import com.redhat.thermostat.thread.client.swing.internal.timeline.RangeComponent; +import com.redhat.thermostat.thread.client.swing.internal.timeline.TimelineComponent; +import com.redhat.thermostat.thread.client.swing.internal.timeline.TimelineContainer; +import com.redhat.thermostat.thread.client.swing.internal.timeline.TimelineViewComponent; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.RangedTimelineProbe; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.TimelineDateFormatter; + +import java.awt.Component; +import java.util.HashMap; +import java.util.Map; + +public class SwingThreadTimelineView extends ThreadTimelineView implements SwingComponent { + + private final UIDefaults uiDefaults; + private TimelineViewComponent contentPane; + + private ComponentVisibilityNotifier visibilityNotifier; + + private Map<ThreadInfo, TimelineComponent> timelines; + + private EDTHelper edt; + + public SwingThreadTimelineView(UIDefaults uiDefaults) { + this.uiDefaults = uiDefaults; + + edt = new EDTHelper(); + timelines = new HashMap<>(); + + this.contentPane = new TimelineViewComponent(uiDefaults); + clear(); + + visibilityNotifier = new ComponentVisibilityNotifier(); + visibilityNotifier.initialize(contentPane, notifier); + } + + @Override + public void addThread(final ThreadInfo thread) { + edt.callLater(new Runnable() { + @Override + public void run() { + if (!timelines.containsKey(thread)) { + TimelineComponent timeline = + new TimelineComponent(uiDefaults, thread, + contentPane.getModel()); + timeline.initComponents(); + + timelines.put(thread, timeline); + contentPane.addTimeline(timeline); + } + } + }); + } + + @Override + public Component getUiComponent() { + return contentPane; + } + + @Override + public void setTotalRange(final Range<Long> totalRange) { + edt.callLater(new Runnable() { + @Override + public void run() { + contentPane.getModel().setRange(totalRange); + } + }); + } + + @Override + public void clear() { + edt.callLater(new Runnable() { + @Override + public void run() { + timelines.clear(); + contentPane.removeAll(); + contentPane.initComponents(); + contentPane.revalidate(); + contentPane.repaint(); + } + }); + } + + @Override + public void addProbe(final ThreadInfo info, final TimelineProbe state) { + edt.callLater(new Runnable() { + @Override + public void run() { + TimelineComponent component = timelines.get(info); + TimelineContainer timelineContainer = + component.getTimelineContainer(); + RangeComponent rangeComponent = + timelineContainer.getLastRangeComponent(); + + if (rangeComponent == null) { + setRangedComponent(state, timelineContainer); + + } else { + RangedTimelineProbe probe = rangeComponent.getInfo(); + probe.setProbeEnd(state.getTimeStamp()); + if (!probe.getColor().equals(state.getColor())) { + setRangedComponent(state, timelineContainer); + } + } + timelineContainer.revalidate(); + timelineContainer.repaint(); + } + }); + } + + private void setRangedComponent(TimelineProbe state, + TimelineContainer timelineContainer) + { + RangedTimelineProbe probe = + new RangedTimelineProbe(state, state.getTimeStamp()); + RangeComponent rangeComponent = new RangeComponent(probe); + rangeComponent.setToolTipText(state.getState() + " - " + + TimelineDateFormatter.format(state. + getTimeStamp())); + timelineContainer.add(rangeComponent); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/SwingThreadView.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,334 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal; + +import com.redhat.thermostat.client.swing.ComponentVisibleListener; +import com.redhat.thermostat.client.swing.SwingComponent; +import com.redhat.thermostat.client.swing.UIDefaults; +import com.redhat.thermostat.client.swing.components.ThermostatTabbedPane; +import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.shared.locale.LocalizedString; +import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.thread.client.common.ThreadTableBean; +import com.redhat.thermostat.thread.client.common.locale.LocaleResources; +import com.redhat.thermostat.thread.client.common.view.LockView; +import com.redhat.thermostat.thread.client.common.view.ThreadCountView; +import com.redhat.thermostat.thread.client.common.view.ThreadTableView; +import com.redhat.thermostat.thread.client.common.view.ThreadTimelineView; +import com.redhat.thermostat.thread.client.common.view.ThreadView; +import com.redhat.thermostat.thread.client.common.view.VmDeadLockView; +import com.redhat.thermostat.thread.model.ThreadSession; + +import javax.swing.JOptionPane; +import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import java.awt.Component; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.List; + +public class SwingThreadView extends ThreadView implements SwingComponent { + + private String DIVIDER_LOCATION_KEY; + + private ThreadMainPanel panel; + + private SwingThreadCountView threadCountView; + private SwingThreadTableView threadTableView; + private SwingVmDeadLockView vmDeadLockView; + private SwingThreadTimelineView threadTimelineView; + private SwingThreadDetailsView threadDetailsView; + private SwingLockView lockView; + + private JTabbedPane topPane; + private JTabbedPane bottomPane; + + private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); + + private boolean skipNotification = false; + + private int threadDetailsPaneID = 0; + + private UIDefaults uiDefaults; + private boolean viewControlsEnabled = true; + + + public SwingThreadView(UIDefaults uiDefaults) { + + this.uiDefaults = uiDefaults; + + panel = new ThreadMainPanel(uiDefaults); + // TODO use ComponentVisiblityNotifier instead + // sadly, the BasicView.notifier field can not be accessed here + panel.addHierarchyListener(new ComponentVisibleListener() { + + @Override + public void componentShown(Component component) { + SwingThreadView.this.notify(Action.VISIBLE); + restoreDivider(); + } + + @Override + public void componentHidden(Component component) { + SwingThreadView.this.notify(Action.HIDDEN); + } + }); + + panel.getSplitPane().addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, + new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + JSplitPane sourceSplitPane = (JSplitPane) evt.getSource(); + saveDivider(sourceSplitPane.getDividerLocation()); + } + }); + + panel.getRecordingToggleButton().setToolTipText(t.localize(LocaleResources.START_RECORDING).getContents()); + panel.getRecordingToggleButton().addItemListener(new ItemListener() + { + @Override + public void itemStateChanged(ItemEvent e) { + + ThreadAction action = null; + if (e.getStateChange() == ItemEvent.SELECTED) { + action = ThreadAction.START_LIVE_RECORDING; + panel.getRecordingToggleButton().setToolTipText(t.localize(LocaleResources.STOP_RECORDING).getContents()); + } else { + action = ThreadAction.STOP_LIVE_RECORDING; + panel.getRecordingToggleButton().setToolTipText(t.localize(LocaleResources.START_RECORDING).getContents()); + } + + if (skipNotification) return; + + final ThreadAction toNotify = action; + SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { + @Override + protected Void doInBackground() throws Exception { + notifier.fireAction(toNotify); + return null; + } + }; + worker.execute(); + } + }); + + panel.getShowRecordedSessionsButton().setToolTipText(t.localize(LocaleResources.RECORDING_LIST_HINT).getContents()); + panel.getShowRecordedSessionsButton().addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() != ItemEvent.SELECTED) { + panel.toggleOverlayPanel(false); + return; + } + + SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { + @Override + protected Void doInBackground() throws Exception { + notifier.fireAction(ThreadAction.REQUEST_DISPLAY_RECORDED_SESSIONS); + return null; + } + }; + worker.execute(); + } + }); + + panel.getSessionsPanel().addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + notifier.fireAction(ThreadAction.REQUEST_LOAD_SESSION, + panel.getSessionsPanel().getSelectedValue()); + } + }); + setupTopPane(); + setupBottomPane(); + } + + private void setupTopPane() { + topPane = new ThermostatTabbedPane(); + topPane.setName("topTabbedPane"); + + threadCountView = new SwingThreadCountView(); + Component comp = threadCountView.getUiComponent(); + comp.setName("count"); + topPane.addTab(t.localize(LocaleResources.THREAD_COUNT).getContents(), comp); + + threadTimelineView = new SwingThreadTimelineView(uiDefaults); + comp = threadTimelineView.getUiComponent(); + comp.setName("timeline"); + topPane.addTab(t.localize(LocaleResources.TIMELINE).getContents(), comp); + + lockView = new SwingLockView(); + comp = lockView.getUiComponent(); + comp.setName("lock"); + topPane.addTab(t.localize(LocaleResources.LOCKS).getContents(), comp); + + panel.getSplitPane().setTopComponent(topPane); + } + + private void setupBottomPane() { + bottomPane = new ThermostatTabbedPane(); + bottomPane.setName("bottomTabbedPane"); + + threadTableView = new SwingThreadTableView(); + bottomPane.addTab(t.localize(LocaleResources.TABLE).getContents(), threadTableView.getUiComponent()); + + threadDetailsView = new SwingThreadDetailsView(); + bottomPane.addTab(t.localize(LocaleResources.DETAILS).getContents(), threadDetailsView.getUiComponent()); + threadDetailsPaneID = 1; + + vmDeadLockView = new SwingVmDeadLockView(); + bottomPane.addTab(t.localize(LocaleResources.VM_DEADLOCK).getContents(), vmDeadLockView.getUiComponent()); + + panel.getSplitPane().setBottomComponent(bottomPane); + } + + @Override + public Component getUiComponent() { + return panel; + } + + @Override + public void setApplicationService(ApplicationService appService, String uniqueId) { + super.setApplicationService(appService, uniqueId); + DIVIDER_LOCATION_KEY = "divider." + uniqueId; + } + + @Override + public void setEnableRecordingControl(final boolean enable) { + this.viewControlsEnabled = enable; + if (!enable) { + setRecording(MonitoringState.DISABLED, false); + } + } + + @Override + public void setRecording(final MonitoringState monitoringState, final boolean notify) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (!notify) skipNotification = true; + if (!viewControlsEnabled) { + panel.getRecordingToggleButton().setToggleActionState(MonitoringState.DISABLED); + } else { + panel.getRecordingToggleButton().setToggleActionState(monitoringState); + } + if (!notify) skipNotification = false; + } + }); + } + + @Override + public VmDeadLockView createDeadLockView() { + return vmDeadLockView; + } + + @Override + public ThreadTableView createThreadTableView() { + return threadTableView; + } + + @Override + public void displayWarning(final LocalizedString warning) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + JOptionPane.showMessageDialog(panel.getParent(), warning.getContents(), "", JOptionPane.WARNING_MESSAGE); + } + }); + } + + private void restoreDivider() { + int location = (int) ((double) (panel.getSplitPane().getHeight() - panel.getSplitPane().getDividerSize()) * 0.80); + if (appService != null) { + Object _location = appService.getApplicationCache().getAttribute(DIVIDER_LOCATION_KEY); + if (_location != null) { + location = (Integer) _location; + } + } + panel.getSplitPane().setDividerLocation(location); + } + + private void saveDivider(int location) { + if (appService != null) { + appService.getApplicationCache().addAttribute(DIVIDER_LOCATION_KEY, location); + } + } + + @Override + public void displayThreadDetails(final ThreadTableBean thread) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + bottomPane.setSelectedIndex(threadDetailsPaneID); + threadDetailsView.setDetails(thread); + } + }); + } + + @Override + public ThreadTimelineView createThreadTimelineView() { + return threadTimelineView; + } + + @Override + public ThreadCountView createThreadCountView() { + return threadCountView; + } + + @Override + public LockView createLockView() { + return lockView; + } + + @Override + public void displayTimelineSessionList(final List<ThreadSession> threadSessions) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + panel.setOverlayContent(threadSessions); + panel.toggleOverlayPanel(true); + } + }); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/SwingVmDeadLockView.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,328 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.FontMetrics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.SwingUtilities; + +import com.mxgraph.layout.mxCircleLayout; +import com.mxgraph.layout.mxEdgeLabelLayout; +import com.mxgraph.layout.mxGraphLayout; +import com.mxgraph.model.mxCell; +import com.mxgraph.swing.mxGraphComponent; +import com.mxgraph.util.mxConstants; +import com.mxgraph.view.mxGraph; +import com.redhat.thermostat.client.swing.SwingComponent; +import com.redhat.thermostat.client.swing.components.ThermostatScrollBar; +import com.redhat.thermostat.client.swing.components.ThermostatScrollPane; +import com.redhat.thermostat.client.swing.components.ThermostatTextArea; +import com.redhat.thermostat.client.swing.experimental.ComponentVisibilityNotifier; +import com.redhat.thermostat.common.utils.StringUtils; +import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.thread.client.common.DeadlockParser; +import com.redhat.thermostat.thread.client.common.DeadlockParser.Information; +import com.redhat.thermostat.thread.client.common.locale.LocaleResources; +import com.redhat.thermostat.thread.client.common.view.VmDeadLockView; + +public class SwingVmDeadLockView extends VmDeadLockView implements SwingComponent { + + private static final Translate<LocaleResources> translate = LocaleResources.createLocalizer(); + + private final JPanel actualComponent = new JPanel(); + private final JButton checkForDeadlockButton; + + private final JSplitPane deadlockTextAndVisualization = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); + + private final JPanel graphical = new JPanel(); + private final ThermostatTextArea description = new ThermostatTextArea(); + /** + * Whether to set the divider's location. Do this only once to set a sane + * initial value but don't change anything after and allow the user to tweak + * this as appropriate. + */ + private boolean dividerLocationSet = false; + + public SwingVmDeadLockView() { + actualComponent.setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.gridy = 0; + c.anchor = GridBagConstraints.LINE_END; + checkForDeadlockButton = new JButton(translate.localize(LocaleResources.CHECK_FOR_DEADLOCKS).getContents()); + checkForDeadlockButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + deadLockNotifier.fireAction(VmDeadLockViewAction.CHECK_FOR_DEADLOCK); + } + }); + + actualComponent.add(checkForDeadlockButton, c); + + c.anchor = GridBagConstraints.LINE_START; + c.gridy++; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + c.weighty = 1; + + description.setEditable(false); + + JScrollPane scrollPane = new ThermostatScrollPane(description); + + graphical.setLayout(new BorderLayout()); + + deadlockTextAndVisualization.setLeftComponent(scrollPane); + deadlockTextAndVisualization.setRightComponent(graphical); + + actualComponent.add(deadlockTextAndVisualization, c); + + new ComponentVisibilityNotifier().initialize(actualComponent, notifier); + } + + @Override + public void setDeadLockInformation(final Information parsed, final String rawText) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + + graphical.removeAll(); + + if (!dividerLocationSet) { + // 0.7 is chosen empirically to show a bit more of the text than the gui + deadlockTextAndVisualization.setDividerLocation(0.7); + deadlockTextAndVisualization.revalidate(); + dividerLocationSet = true; + } + + if (parsed != null) { + FontMetrics metrics = graphical.getGraphics().getFontMetrics(); + graphical.add(createGraph(parsed, metrics), BorderLayout.CENTER); + } + + graphical.revalidate(); + graphical.repaint(); + + description.setText(rawText); + } + }); + } + + private mxGraphComponent createGraph(Information info, FontMetrics fontMetrics) { + + final mxGraph graph = new mxGraph() { + + /* Show tooltips for vertices and edges */ + @Override + public String getToolTipForCell(Object source) { + mxCell cell = ((mxCell) source); + + if (cell.getValue() instanceof GraphItem) { + return ((GraphItem) cell.getValue()).getTooltip(); + } else { + return super.getToolTipForCell(cell); + } + } + + + /* Prevent modifying the contents of edges or vertices */ + @Override + public boolean isCellEditable(Object cell) { + return false; + } + + /* Prevent moving edges away from the vertices */ + @Override + public boolean isCellSelectable(Object cell) { + return !model.isEdge(cell); + } + + }; + + Object parent = graph.getDefaultParent(); + + addDeadlockToGraph(info, graph, parent, fontMetrics); + + graph.setAutoSizeCells(true); + graph.setCellsResizable(true); + + final mxGraphComponent graphComponent = new mxGraphComponent(graph); + graphComponent.setTextAntiAlias(true); + graphComponent.setToolTips(true); + graphComponent.setConnectable(false); + + graphComponent.setHorizontalScrollBar(new ThermostatScrollBar(ThermostatScrollBar.HORIZONTAL)); + graphComponent.setVerticalScrollBar(new ThermostatScrollBar(ThermostatScrollBar.VERTICAL)); + + Map<String, Object> style = graph.getStylesheet().getDefaultVertexStyle(); + style.put(mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER); + graph.getStylesheet().setDefaultVertexStyle(style); + + mxGraphLayout layout = new mxCircleLayout(graph); + layout.execute(graph.getDefaultParent()); + + layout = new mxEdgeLabelLayout(graph); + layout.execute(graph.getDefaultParent()); + + return graphComponent; + } + + @Override + public void setCheckDeadlockControlEnabled(final boolean enabled) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + SwingVmDeadLockView.this.checkForDeadlockButton.setEnabled(enabled); + } + }); + } + + private static void addDeadlockToGraph(Information info, mxGraph graph, Object parent, FontMetrics metrics) { + graph.getModel().beginUpdate(); // batch updates + try { + Map<String, Object> idToCell = new HashMap<>(); + Map<String, String> idToLabel = new HashMap<>(); + + for (DeadlockParser.Thread thread : info.threads) { + String label = getThreadLabel(thread); + String tooltip = getThreadTooltip(thread); + idToLabel.put(thread.id, label); + GraphItem node = new GraphItem(label, tooltip); + final int PADDING = 20; + int width = metrics.stringWidth(label) + PADDING; + int height = metrics.getHeight() + PADDING; + Object threadNode = graph.insertVertex(parent, thread.id, node, 0, 0, width, height); + idToCell.put(thread.id, threadNode); + } + + for (DeadlockParser.Thread thread : info.threads) { + String label = translate.localize(LocaleResources.DEADLOCK_WAITING_ON).getContents(); + String tooltip = getEdgeTooltip(thread, idToLabel); + GraphItem edge = new GraphItem(label, tooltip); + graph.insertEdge(parent, thread.waitingOn.name, edge, idToCell.get(thread.id), idToCell.get(thread.waitingOn.ownerId)); + } + + } finally { + graph.getModel().endUpdate(); + } + } + + private static String getThreadLabel(DeadlockParser.Thread thread) { + return translate.localize(LocaleResources.DEADLOCK_THREAD_NAME, thread.name, thread.id).getContents(); + } + + private static String getThreadTooltip(DeadlockParser.Thread thread) { + return translate.localize( + LocaleResources.DEADLOCK_THREAD_TOOLTIP, + StringUtils.htmlEscape(thread.waitingOn.name), + stackTraceToHtmlString(thread.stackTrace)) + .getContents(); + } + + private static String stackTraceToHtmlString(List<String> items) { + StringBuilder result = new StringBuilder(); + for (String item : items) { + result.append(StringUtils.htmlEscape(item)).append("<br/>"); + } + return result.toString(); + } + + private static String getEdgeTooltip(DeadlockParser.Thread thread, Map<String, String> idToLabel) { + return translate.localize( + LocaleResources.DEADLOCK_EDGE_TOOLTIP, + idToLabel.get(thread.id), + idToLabel.get(thread.waitingOn.ownerId)) + .getContents(); + } + + @Override + public Component getUiComponent() { + return actualComponent; + } + + static class GraphItem implements Serializable { + + private final String label; + private final String tooltip; + + public GraphItem(String label, String tooltip) { + this.label = label; + this.tooltip = tooltip; + } + + @Override + public int hashCode() { + return Objects.hash(label, tooltip); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + GraphItem other = (GraphItem) obj; + return Objects.equals(label, other.label) && Objects.equals(tooltip, other.tooltip); + } + + @Override + public String toString() { + return label; + } + + public String getTooltip() { + return tooltip; + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/ThreadAliveDaemonTimelinePanel.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,132 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal; + +import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.thread.client.common.locale.LocaleResources; + +import javax.swing.BoxLayout; +import javax.swing.GroupLayout; +import javax.swing.GroupLayout.Alignment; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.LayoutStyle.ComponentPlacement; +import javax.swing.SwingConstants; + +@SuppressWarnings("serial") +class ThreadAliveDaemonTimelinePanel extends JPanel { + + private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); + + private JLabel liveThreads; + private JLabel daemonThreads; + private JPanel timelinePanel; + + /** + * Create the panel. + */ + public ThreadAliveDaemonTimelinePanel() { + JPanel runningPanel = new JPanel(); + + timelinePanel = new JPanel(); + timelinePanel.setOpaque(false); + timelinePanel.setLayout(new BoxLayout(timelinePanel, BoxLayout.X_AXIS)); + + GroupLayout groupLayout = new GroupLayout(this); + groupLayout.setHorizontalGroup( + groupLayout.createParallelGroup(Alignment.TRAILING) + .addComponent(runningPanel, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 577, Short.MAX_VALUE) + .addComponent(timelinePanel, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 577, Short.MAX_VALUE) + ); + groupLayout.setVerticalGroup( + groupLayout.createParallelGroup(Alignment.LEADING) + .addGroup(groupLayout.createSequentialGroup() + .addComponent(runningPanel, GroupLayout.PREFERRED_SIZE, 41, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(ComponentPlacement.RELATED) + .addComponent(timelinePanel, GroupLayout.DEFAULT_SIZE, 254, Short.MAX_VALUE)) + ); + + JLabel liveThreadsLabel = new JLabel(t.localize(LocaleResources.LIVE_THREADS).getContents() + ":"); + + JLabel daemonThreadsLabel = new JLabel(t.localize(LocaleResources.DAEMON_THREADS).getContents() + ":"); + + liveThreads = new JLabel("-"); + liveThreads.setHorizontalAlignment(SwingConstants.RIGHT); + + daemonThreads = new JLabel("-"); + daemonThreads.setHorizontalAlignment(SwingConstants.RIGHT); + GroupLayout gl_runningPanel = new GroupLayout(runningPanel); + gl_runningPanel.setHorizontalGroup( + gl_runningPanel.createParallelGroup(Alignment.LEADING) + .addGroup(gl_runningPanel.createSequentialGroup() + .addComponent(liveThreadsLabel) + .addGap(18) + .addComponent(liveThreads, GroupLayout.PREFERRED_SIZE, 85, GroupLayout.PREFERRED_SIZE) + .addGap(18) + .addComponent(daemonThreadsLabel) + .addPreferredGap(ComponentPlacement.RELATED) + .addComponent(daemonThreads, GroupLayout.PREFERRED_SIZE, 49, GroupLayout.PREFERRED_SIZE) + .addContainerGap(54, Short.MAX_VALUE)) + ); + gl_runningPanel.setVerticalGroup( + gl_runningPanel.createParallelGroup(Alignment.TRAILING) + .addGroup(Alignment.LEADING, gl_runningPanel.createSequentialGroup() + .addGroup(gl_runningPanel.createParallelGroup(Alignment.BASELINE) + .addComponent(liveThreadsLabel) + .addComponent(liveThreads) + .addComponent(daemonThreads) + .addComponent(daemonThreadsLabel)) + .addContainerGap(26, Short.MAX_VALUE)) + ); + runningPanel.setLayout(gl_runningPanel); + setLayout(groupLayout); + + } + + public JLabel getLiveThreads() { + return liveThreads; + } + + public JLabel getDaemonThreads() { + return daemonThreads; + } + + public JPanel getTimelinePanel() { + return timelinePanel; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/ThreadDetailsChart.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,49 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal; + +import javax.swing.BoxLayout; +import javax.swing.JPanel; + +@SuppressWarnings("serial") +public class ThreadDetailsChart extends JPanel { + + public ThreadDetailsChart() { + setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/ThreadMainPanel.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,269 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal; + +import com.redhat.thermostat.client.swing.IconResource; +import com.redhat.thermostat.client.swing.UIDefaults; +import com.redhat.thermostat.client.swing.components.ActionToggleButton; +import com.redhat.thermostat.client.swing.components.FontAwesomeIcon; +import com.redhat.thermostat.client.swing.components.HeaderPanel; +import com.redhat.thermostat.client.swing.components.Icon; +import com.redhat.thermostat.client.swing.components.OverlayPanel; +import com.redhat.thermostat.client.swing.components.ShadowLabel; +import com.redhat.thermostat.client.swing.components.ThermostatScrollPane; +import com.redhat.thermostat.client.swing.components.ThermostatThinScrollBar; +import com.redhat.thermostat.client.ui.Palette; +import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.thread.client.common.locale.LocaleResources; +import com.redhat.thermostat.thread.model.ThreadSession; + +import javax.swing.BoxLayout; +import javax.swing.DefaultListModel; +import javax.swing.GroupLayout; +import javax.swing.GroupLayout.Alignment; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JSplitPane; +import javax.swing.ListCellRenderer; +import javax.swing.ListModel; +import javax.swing.ListSelectionModel; +import javax.swing.OverlayLayout; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Point; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.Date; +import java.util.List; + +@SuppressWarnings("serial") +class ThreadMainPanel extends JPanel { + + private static final Icon START_ICON = IconResource.SAMPLE.getIcon(); + private final Icon stopIcon; + + private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); + private JSplitPane splitPane; + + private ActionToggleButton toggleButton; + private ActionToggleButton showRecordedSessionsButton; + + private OverlayPanel overlay; + + private UIDefaults uiDefaults; + private ThreadSessionList sessionsPanel; + private DefaultListModel<ThreadSession> sessionsModel; + + @Override + public boolean isOptimizedDrawingEnabled() { + return false; + } + + public ThreadMainPanel(UIDefaults uiDefaults) { + this.uiDefaults = uiDefaults; + + setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); + + HeaderPanel headerPanel = new HeaderPanel(); + headerPanel.setHeader(t.localize(LocaleResources.THREAD_CONTROL_PANEL)); + + stopIcon = new FontAwesomeIcon('\uf28e', START_ICON.getIconHeight(), uiDefaults.getIconColor()); + + toggleButton = new ActionToggleButton(START_ICON, stopIcon, t.localize(LocaleResources.THREAD_MONITOR_SWITCH)); + toggleButton.setName("recordButton"); + headerPanel.addToolBarButton(toggleButton); + + Icon listSessionsIcon = IconResource.HISTORY.getIcon(); + showRecordedSessionsButton = new ActionToggleButton(listSessionsIcon, t.localize(LocaleResources.THREAD_MONITOR_DISPLAY_SESSIONS)); + showRecordedSessionsButton.setName("showRecordedSessionsButton"); + headerPanel.addToolBarButton(showRecordedSessionsButton); + + overlay = new OverlayPanel(t.localize(LocaleResources.RECORDING_LIST), true, true); + overlay.setName("threadOverlayPanel"); + overlay.addCloseEventListener(new OverlayPanel.CloseEventListener() { + @Override + public void closeRequested(OverlayPanel.CloseEvent event) { + showRecordedSessionsButton.doClick(); + } + }); + + JPanel stack = new JPanel(); + stack.setName("threadStackPanel"); + stack.setOpaque(true); + stack.setLayout(new OverlayLayout(stack)); + + splitPane = new JSplitPane(); + splitPane.setName("threadMainPanelSplitPane"); + splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); + splitPane.setOneTouchExpandable(true); + + JPanel content = new JPanel(); + GroupLayout gl_content = new GroupLayout(content); + gl_content.setHorizontalGroup( + gl_content.createParallelGroup(Alignment.TRAILING) + .addGroup(Alignment.LEADING, gl_content.createSequentialGroup() + .addContainerGap() + .addComponent(splitPane, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) + ); + gl_content.setVerticalGroup( + gl_content.createParallelGroup(Alignment.TRAILING) + .addGroup(Alignment.LEADING, gl_content.createSequentialGroup() + .addContainerGap() + .addComponent(splitPane, 0, 240, Short.MAX_VALUE) + .addContainerGap()) + ); + + content.setLayout(gl_content); + + stack.add(overlay); + stack.add(content); + stack.setOpaque(false); + + headerPanel.setContent(stack); + + add(headerPanel); + + sessionsModel = new DefaultListModel<>(); + + sessionsPanel = new ThreadSessionList(sessionsModel); + sessionsPanel.setSelectionMode(JList.VERTICAL); + sessionsPanel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + sessionsPanel.setOpaque(false); + sessionsPanel.setCellRenderer(new ThreadSessionRenderer()); + sessionsPanel.addMouseMotionListener(new MouseAdapter() { + @Override + public void mouseMoved(MouseEvent e) { + Point where = new Point(e.getX(), e.getY()); + int index = sessionsPanel.locationToIndex(where); + int hoveredIndex = sessionsPanel.getHoveredIndex(); + if (index != hoveredIndex) { + sessionsPanel.setHoveredIndex(index); + sessionsPanel.repaint(); + } + } + }); + ThermostatScrollPane scrollPane = new ThermostatScrollPane(sessionsPanel); + scrollPane.setVerticalScrollBar(new ThermostatThinScrollBar(ThermostatThinScrollBar.VERTICAL)); + overlay.add(scrollPane); + } + + public ThreadSessionList getSessionsPanel() { + return sessionsPanel; + } + + public JSplitPane getSplitPane() { + return splitPane; + } + + public ActionToggleButton getRecordingToggleButton() { + return toggleButton; + } + + public ActionToggleButton getShowRecordedSessionsButton() { + return showRecordedSessionsButton; + } + + public void toggleOverlayPanel(boolean visible) { + overlay.setOverlayVisible(visible); + } + + public class ThreadSessionRenderer implements ListCellRenderer<ThreadSession> { + + @Override + public Component getListCellRendererComponent(JList<? extends ThreadSession> list, + ThreadSession value, int index, + boolean isSelected, + boolean cellHasFocus) + { + JPanel panel = new JPanel(); + panel.setLayout(new BorderLayout()); + panel.setOpaque(false); + ShadowLabel label = new ShadowLabel(); + label.setText("[" + new Date(value.getTimeStamp()) +"]"); + label.setOpaque(false); + + if (isSelected || cellHasFocus) { + panel.setOpaque(true); + panel.setBackground((Color) uiDefaults.getSelectedComponentBGColor()); + label.setForeground((Color) uiDefaults.getSelectedComponentFGColor()); + + } else if ((sessionsPanel.getHoveredIndex() == index)) { + panel.setOpaque(true); + panel.setBackground(Palette.ELEGANT_CYAN.getColor()); + label.setForeground((Color) uiDefaults.getSelectedComponentFGColor()); + + } else { + label.setForeground((Color) uiDefaults.getComponentFGColor()); + } + + panel.add(label); + return panel; + } + } + + public void setOverlayContent(List<ThreadSession> threadSessions) { + sessionsModel.clear(); + + for (ThreadSession session : threadSessions) { + sessionsModel.addElement(session); + } + sessionsPanel.setHoveredIndex(-1); + + overlay.revalidate(); + overlay.repaint(); + + } + + public class ThreadSessionList extends JList<ThreadSession> { + private int hoveredIndex; + public ThreadSessionList(ListModel<ThreadSession> dataModel) { + super(dataModel); + hoveredIndex = -1; + } + + public int getHoveredIndex() { + return hoveredIndex; + } + + public void setHoveredIndex(int hoveredIndex) { + this.hoveredIndex = hoveredIndex; + } + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/ThreadTable.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,51 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal; + +import javax.swing.JPanel; +import javax.swing.BoxLayout; + +@SuppressWarnings("serial") +public class ThreadTable extends JPanel { + /** + * Create the panel. + */ + public ThreadTable() { + setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/timeline/RangeComponent.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,66 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal.timeline; + +import com.redhat.thermostat.thread.client.swing.experimental.components.ContentPane; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.RangedTimelineProbe; + +import java.awt.Graphics; +import java.awt.Rectangle; + +/** + * + */ +public class RangeComponent extends ContentPane { + private RangedTimelineProbe info; + + public RangeComponent(RangedTimelineProbe info) { + this.info = info; + setOpaque(false); + } + + public RangedTimelineProbe getInfo() { + return info; + } + + @Override + protected void paintComponent(Graphics g) { + g.setColor(info.getColor().getColor()); + Rectangle bounds = g.getClipBounds(); + g.fillRect(bounds.x, bounds.y, bounds.width - 1, bounds.height - 1); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/timeline/RangeComponentHeader.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,159 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal.timeline; + +import com.redhat.thermostat.client.swing.UIDefaults; +import com.redhat.thermostat.client.swing.components.FontAwesomeIcon; +import com.redhat.thermostat.client.swing.components.Icon; +import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.thread.client.common.locale.LocaleResources; +import com.redhat.thermostat.thread.client.swing.experimental.components.ContentPane; +import com.redhat.thermostat.thread.client.swing.experimental.components.DataPane; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.TimelineModel; + +import java.awt.BorderLayout; +import java.awt.GridLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.JLabel; + +/** + * + */ +public class RangeComponentHeader extends ContentPane { + + private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); + + private final TimelineModel model; + private final UIDefaults defaults; + private DataPane controls; + + private JLabel zoomOut; + private JLabel restoreZoom; + private JLabel zoomIn; + + public RangeComponentHeader(TimelineModel model, UIDefaults defaults) { + this.model = model; + this.defaults = defaults; + } + + public void initComponents() { + controls = new DataPane(); + controls.setLayout(new GridLayout(1, 0, 5, 5)); + + Icon baseIcon = new FontAwesomeIcon('\uf066', 15, defaults.getIconColor()); + Icon hoverIcon = new FontAwesomeIcon('\uf066', 15, + defaults.getSelectedComponentBGColor()); + zoomOut = new JLabel(baseIcon); + zoomOut.setToolTipText(t.localize(LocaleResources.ZOOM_OUT).getContents()); + zoomOut.addMouseListener(new Hover(zoomOut, baseIcon, hoverIcon)); + zoomOut.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + double ratio = model.getMagnificationRatio(); + model.setMagnificationRatio(ratio/2); + } + }); + controls.add(zoomOut); + + baseIcon = new FontAwesomeIcon('\uf03b', 15, defaults.getIconColor()); + hoverIcon = new FontAwesomeIcon('\uf03b', 15, + defaults.getSelectedComponentBGColor()); + restoreZoom = new JLabel(baseIcon); + restoreZoom.setToolTipText(t.localize(LocaleResources.RESTORE_ZOOM).getContents()); + restoreZoom.addMouseListener(new Hover(restoreZoom, baseIcon, hoverIcon)); + restoreZoom.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + model.setMagnificationRatio(TimelineModel.DEFAULT_RATIO); + } + }); + controls.add(restoreZoom); + + baseIcon = new FontAwesomeIcon('\uf065', 15, defaults.getIconColor()); + hoverIcon = new FontAwesomeIcon('\uf065', 15, + defaults.getSelectedComponentBGColor()); + zoomIn = new JLabel(baseIcon); + zoomIn.setToolTipText(t.localize(LocaleResources.ZOOM_IN).getContents()); + zoomIn.addMouseListener(new Hover(zoomIn, baseIcon, hoverIcon)); + zoomIn.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + double ratio = model.getMagnificationRatio(); + model.setMagnificationRatio(ratio*2); + } + }); + controls.add(zoomIn); + + add(controls, BorderLayout.EAST); + } + + public void setControlsEnabled(boolean b) { + zoomIn.setEnabled(b); + zoomOut.setEnabled(b); + restoreZoom.setEnabled(b); + } + + private class Hover extends MouseAdapter { + + private final JLabel label; + private final Icon baseIcon; + private final Icon hoverIcon; + + public Hover(JLabel label, Icon baseIcon, Icon hoverIcon) { + + this.label = label; + this.baseIcon = baseIcon; + this.hoverIcon = hoverIcon; + } + + @Override + public void mouseEntered(MouseEvent e) { + onMouseHover(true); + } + + @Override + public void mouseExited(MouseEvent e) { + onMouseHover(false); + } + + public void onMouseHover(boolean hover) { + label.setIcon(hover ? hoverIcon : baseIcon); + repaint(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/timeline/RangeComponentLayoutManager.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,105 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal.timeline; + +import com.redhat.thermostat.client.swing.components.AbstractLayout; +import com.redhat.thermostat.common.model.LongRangeNormalizer; +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.RangedTimelineProbe; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.TimelineModel; + +import java.awt.Container; +import java.awt.Dimension; + +/** + * + */ +class RangeComponentLayoutManager extends AbstractLayout { + + private static final int STATE_COMPONENT_HEIGHT = 5; + + private static final boolean DEBUG_TIMELINES = false; + + @Override + protected void doLayout(Container parent) { + TimelineContainer container = (TimelineContainer) parent; + + Dimension size = getRealLayoutSize(container); + TimelineModel model = container.getModel(); + + LongRangeNormalizer normalizer = new LongRangeNormalizer(model.getRange()); + + normalizer.setMinNormalized(0); + normalizer.setMaxNormalized(size.width); + + if (DEBUG_TIMELINES) System.err.print(container.getName()); + + for (RangeComponent rangeComponent : container) { + + RangedTimelineProbe info = rangeComponent.getInfo(); + Range<Long> range = info.getRange(); + int x = (int) normalizer.getValueNormalized(range.getMin()); + int width = (int) normalizer.getValueNormalized(range.getMax()) - x + 1; + + rangeComponent.setBounds(x, 0, width, 5); + + if (DEBUG_TIMELINES) System.err.print(" [" + range.getMin() + + " - " + range.getMax() + "]"); + } + + if (DEBUG_TIMELINES) System.err.println(""); + } + + @Override + public Dimension preferredLayoutSize(Container parent) { + return getRealLayoutSize(parent); + } + + public Dimension getRealLayoutSize(Container parent) { + TimelineContainer container = (TimelineContainer) parent; + + TimelineModel model = container.getModel(); + + Range<Long> range = model.getRange(); + + double length = range.getMax() - range.getMin(); + double multiplier = model.getMagnificationRatio(); + + return new Dimension((int) Math.round(length * multiplier), + STATE_COMPONENT_HEIGHT); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/timeline/RulerComponent.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,165 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal.timeline; + +import com.redhat.thermostat.client.swing.GraphicsUtils; +import com.redhat.thermostat.client.swing.UIDefaults; +import com.redhat.thermostat.client.ui.Palette; +import com.redhat.thermostat.thread.client.swing.experimental.components.DataPane; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.TimelineModel; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; + +/** + * + */ +public class RulerComponent extends DataPane { + + protected class RenderingInfo { + long startRendering; + long stopRendering; + + long startMark; + long increment; + } + + protected final UIDefaults uiDefaults; + protected TimelineModel model; + private boolean selected; + + public RulerComponent(UIDefaults defaults, TimelineModel model) { + + super(Palette.LIGHT_GRAY, Palette.WHITE); + + this.uiDefaults = defaults; + this.model = model; + setFont(defaults.getDefaultFont().deriveFont(Font.PLAIN, 10.f)); + setName("ruler"); + } + + public boolean isSelected() { + return selected; + } + + public void setSelected(boolean selected) { + this.selected = selected; + } + + @Override + public Dimension getPreferredSize() { + Dimension pref = super.getPreferredSize(); + pref.height = getHeight(); + return pref; + } + + @Override + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + @Override + public Dimension getSize() { + return getPreferredSize(); + } + + private RenderingInfo getRenderingInfo(Rectangle bounds) { + + RenderingInfo info = new RenderingInfo(); + info.stopRendering = bounds.x + bounds.width; + info.increment = 10; + + long start = model.getRange().getMin(); + long visibleStartTime = start + model.getScrollBarModel().getValue(); + + // small mark, 1 second boundary + long mark = visibleStartTime - (1_000 * (visibleStartTime/1_000)); + info.startRendering = -mark; + + return info; + } + + @Override + protected void paintComponent(Graphics g) { + Graphics2D graphics = GraphicsUtils.getInstance().createAAGraphics(g); + + Rectangle bounds = graphics.getClipBounds(); + if (!isSelected()) { + super.paintComponent(g); + } else { + graphics.setPaint(uiDefaults.getSelectedComponentBGColor()); + graphics.fillRect(bounds.x, bounds.y, bounds.width, bounds.height); + } + + Color lines = Palette.PALE_GRAY.getColor(); + Color tickLines = Palette.DARK_GRAY.getColor(); + + RenderingInfo info = getRenderingInfo(bounds); + int height = bounds.y + bounds.height; + + boolean resetColor = false; + long mark = 10l; + + graphics.setColor(lines); + for (int i = (int) info.startRendering, j = (int) info.startMark; + i < info.stopRendering; i += info.increment, j++) + { + if (j % mark == 0) { + graphics.setColor(tickLines); + resetColor = true; + } + + graphics.drawLine(i, bounds.y, i, height); + + if (resetColor) { + graphics.setColor(lines); + resetColor = false; + } + } + + // TODO +// if (drawLabels) { +// drawLabels(graphics, info); +// } + + graphics.dispose(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/timeline/TimelineAdjustmentListener.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal.timeline; + +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; +import javax.swing.BoundedRangeModel; + +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.TimelineModel; + +/** + * + */ +public class TimelineAdjustmentListener implements AdjustmentListener { + + private TimelineModel model; + private boolean followMode; + + public TimelineAdjustmentListener(TimelineModel model) { + this.model = model; + } + + @Override + public void adjustmentValueChanged(AdjustmentEvent e) { + BoundedRangeModel scrollBarModel = model.getScrollBarModel(); + if (scrollBarModel.getValueIsAdjusting()) { + followMode = false; + return; + } + + int max = scrollBarModel.getMaximum(); + int currentExtent = scrollBarModel.getValue() + + scrollBarModel.getExtent(); + + if (currentExtent == max) { + followMode = true; + } + + if (followMode) { + int value = max - scrollBarModel.getExtent(); + scrollBarModel.setValue(value); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/timeline/TimelineComponent.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,155 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal.timeline; + +import com.redhat.thermostat.client.swing.UIDefaults; +import com.redhat.thermostat.client.swing.components.ThermostatScrollPane; +import com.redhat.thermostat.thread.client.common.model.timeline.ThreadInfo; +import com.redhat.thermostat.thread.client.swing.experimental.components.ContentPane; +import com.redhat.thermostat.thread.client.swing.experimental.components.Separator; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.TimelineModel; + +import java.awt.BorderLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +/** + * + */ +public class TimelineComponent extends RulerComponent { + + private static final int MIN_HEIGHT = 50; + private final ThreadInfo threadInfo; + + private ContentPane labelPane; + + private TimelineLabel label; + + private ThermostatScrollPane scrollPane; + private TimelineContainer timelineContainer; + + public TimelineComponent(UIDefaults uiDefaults, ThreadInfo threadInfo, + TimelineModel model) + { + super(uiDefaults, model); + this.threadInfo = threadInfo; + } + + public void initComponents() { + setName(threadInfo.getName()); + + initModel(); + + initLabelPane(); + initThreadPane(); + + setBorder(new Separator(uiDefaults, Separator.Side.BOTTOM, + Separator.Type.SOLID)); + + Hover hover = new Hover(); + addMouseListener(hover); + } + + private void initModel() { + model.getScrollBarModel().addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + repaint(); + } + }); + } + + private void initThreadPane() { + + timelineContainer = new TimelineContainer(model); + timelineContainer.setName(threadInfo.getName()); + + scrollPane = new ThermostatScrollPane(timelineContainer); + scrollPane.setHorizontalScrollBarPolicy(ThermostatScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + scrollPane.setVerticalScrollBarPolicy(ThermostatScrollPane.VERTICAL_SCROLLBAR_NEVER); + + add(scrollPane, BorderLayout.CENTER); + + scrollPane.getHorizontalScrollBar().setModel(model.getScrollBarModel()); + } + + public TimelineContainer getTimelineContainer() { + return timelineContainer; + } + + private void initLabelPane() { + label = new TimelineLabel(uiDefaults, getName()); + labelPane = new ContentPane(); + + labelPane.setOpaque(false); + labelPane.setLayout(new GridBagLayout()); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.anchor = GridBagConstraints.WEST; + gbc.fill = GridBagConstraints.NONE; + gbc.weightx = 1.f; + + labelPane.add(label, gbc); + add(labelPane, BorderLayout.NORTH); + } + + @Override + public int getHeight() { + return MIN_HEIGHT; + } + + private class Hover extends MouseAdapter { + @Override + public void mouseEntered(MouseEvent e) { + onMouseHover(true); + } + + @Override + public void mouseExited(MouseEvent e) { + onMouseHover(false); + } + + public void onMouseHover(boolean hover) { + label.onMouseHover(hover); + repaint(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/timeline/TimelineContainer.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,104 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal.timeline; + +import com.redhat.thermostat.thread.client.swing.experimental.components.ContentPane; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.RangeChangeEvent; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.RangeChangeListener; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.RatioChangeEvent; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.RatioChangeListener; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.TimelineModel; + +import java.awt.Component; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * + */ +public class TimelineContainer extends ContentPane implements Iterable<RangeComponent> { + + private List<RangeComponent> rangeComponents; + private TimelineModel model; + + public TimelineContainer(TimelineModel model) { + rangeComponents = new ArrayList<>(); + + setOpaque(false); + setLayout(new RangeComponentLayoutManager()); + + setModel(model); + } + + public Component add(RangeComponent comp) { + rangeComponents.add(comp); + return super.add(comp); + } + + @Override + public Iterator<RangeComponent> iterator() { + return rangeComponents.iterator(); + } + + public TimelineModel getModel() { + return model; + } + + public void setModel(TimelineModel model) { + this.model = model; + model.addRangeChangeListener(new RangeChangeListener() { + @Override + public void rangeChanged(RangeChangeEvent event) { + revalidate(); + repaint(); + } + }); + model.addRatioChangeListener(new RatioChangeListener() { + @Override + public void ratioChanged(RatioChangeEvent event) { + revalidate(); + repaint(); + } + }); + } + + public RangeComponent getLastRangeComponent() { + return rangeComponents.isEmpty() ? null : + rangeComponents.get(rangeComponents.size() - 1); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/timeline/TimelineLabel.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,91 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal.timeline; + +import com.redhat.thermostat.client.swing.UIDefaults; +import com.redhat.thermostat.client.swing.components.Icon; +import com.redhat.thermostat.client.swing.components.LabelField; +import com.redhat.thermostat.client.ui.Palette; +import com.redhat.thermostat.shared.locale.LocalizedString; +import com.redhat.thermostat.thread.client.swing.experimental.components.DataPane; +import com.redhat.thermostat.thread.client.swing.experimental.components.Separator; +import java.awt.Color; +import javax.swing.SwingConstants; +import javax.swing.border.EmptyBorder; + +/** + * + */ +class TimelineLabel extends DataPane { + private LabelField nameLabel; + private Icon infoOn; + private Icon infoOff; + + TimelineLabel(UIDefaults defaults, String text) { + super(Palette.WHITE, Palette.LIGHT_GRAY); + + setBorder(new Separator(defaults, Separator.Side.BOTTOM, Separator.Type.SOLID)); + + nameLabel = new LabelField(LocalizedString.EMPTY_STRING); + nameLabel.setFont(defaults.getDefaultFont().deriveFont(10.f)); + + nameLabel.setText(text); + nameLabel.setHorizontalAlignment(SwingConstants.CENTER); + nameLabel.setVerticalAlignment(SwingConstants.CENTER); + nameLabel.setForeground((Color) defaults.getSelectedComponentBGColor()); + + // make same small space around the label, a bit higher left and right + // to account for the missing icon + nameLabel.setBorder(new EmptyBorder(2, 4, 2, 4)); + + nameLabel.setHorizontalTextPosition(SwingConstants.LEFT); + + // FIXME && TODO: comment this out for now, the functionality this is + // meant for is not yet implemented in the controller +// infoOn = new FontAwesomeIcon('\uf05a', 12, Palette.DARK_GRAY.getColor()); +// infoOff = new FontAwesomeIcon('\uf05a', 12, Palette.PALE_GRAY.getColor()); +// +// nameLabel.setIcon(infoOff); + + add(nameLabel); + } + + public void onMouseHover(boolean hover) { +// nameLabel.setIcon(hover ? infoOn : infoOff); + repaint(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/timeline/TimelineViewComponent.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,153 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal.timeline; + +import com.redhat.thermostat.client.swing.UIDefaults; +import com.redhat.thermostat.client.swing.components.ThermostatScrollBar; +import com.redhat.thermostat.client.swing.components.ThermostatScrollPane; +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.thread.client.swing.experimental.components.ContentPane; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.LegendPanel; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.RangeChangeEvent; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.RangeChangeListener; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.RatioChangeEvent; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.RatioChangeListener; +import com.redhat.thermostat.thread.client.swing.internal.timeline.model.TimelineModel; + +import java.awt.BorderLayout; +import java.awt.Rectangle; + +/** + * + */ +public class TimelineViewComponent extends ContentPane { + + private TimelineModel model; + private ThermostatScrollPane scrollPane; + private TimelineViewport viewport; + + private ThermostatScrollBar scrollBar; + private UIDefaults uiDefaults; + private RangeComponentHeader header; + + public TimelineViewComponent(UIDefaults uiDefaults) { + this.uiDefaults = uiDefaults; + } + + public void initComponents() { + + ContentPane contentPane = new ContentPane(); + + this.model = new TimelineModel(); + + viewport = new TimelineViewport(); + + scrollPane = new ThermostatScrollPane(viewport); + scrollPane.setVerticalScrollBarPolicy(ThermostatScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + scrollPane.setHorizontalScrollBarPolicy(ThermostatScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + + header = new RangeComponentHeader(model, uiDefaults); + header.initComponents(); + scrollPane.setColumnHeaderView(header); + + contentPane.add(scrollPane, BorderLayout.CENTER); + + scrollBar = new ThermostatScrollBar(ThermostatScrollBar.HORIZONTAL); + model.setScrollBarModel(scrollBar.getModel()); + + scrollBar.addAdjustmentListener(new TimelineAdjustmentListener(model)); + + contentPane.add(scrollBar, BorderLayout.SOUTH); + scrollBar.setEnabled(false); + scrollBar.setVisible(false); + + header.setControlsEnabled(false); + + add(contentPane, BorderLayout.CENTER); + + LegendPanel legend = new LegendPanel(uiDefaults); + add(legend, BorderLayout.SOUTH); + + model.addRatioChangeListener(new RatioChangeListener() { + @Override + public void ratioChanged(RatioChangeEvent event) { + checkEnableScrollbar(); + } + }); + model.addRangeChangeListener(new RangeChangeListener() { + @Override + public void rangeChanged(RangeChangeEvent event) { + checkEnableScrollbar(); + } + }); + } + + private void checkEnableScrollbar() { + Range<Long> range = model.getRange(); + // no data, so no scrolling + if (range == null) { + scrollBar.setVisible(false); + scrollBar.setEnabled(false); + return; + } + + Rectangle bounds = getBounds(); + long length = bounds.x + bounds.width; + length = Math.round(length / model.getMagnificationRatio()); + + long lengthInMs = range.getMax() - range.getMin(); + lengthInMs = Math.round(lengthInMs / model.getMagnificationRatio()); + + boolean shouldEnable = (length < lengthInMs); + + scrollBar.setVisible(shouldEnable); + scrollBar.setEnabled(shouldEnable); + } + + public void addTimeline(TimelineComponent timeline) { + viewport.add(timeline); + header.setControlsEnabled(true); + checkEnableScrollbar(); + revalidate(); + repaint(); + } + + public TimelineModel getModel() { + return model; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/timeline/TimelineViewport.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal.timeline; + +import com.redhat.thermostat.thread.client.swing.experimental.components.ContentPane; +import java.awt.Dimension; +import java.awt.Rectangle; +import javax.swing.BoxLayout; +import javax.swing.Scrollable; + +/** + * + */ +public class TimelineViewport extends ContentPane implements Scrollable { + + public TimelineViewport() { + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + } + + @Override + public Dimension getPreferredScrollableViewportSize() { + return getPreferredSize(); + } + + @Override + public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { + return 1; + } + + @Override + public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { + return 1; + } + + @Override + public boolean getScrollableTracksViewportWidth() { + return true; + } + + @Override + public boolean getScrollableTracksViewportHeight() { + return false; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/timeline/model/LegendPanel.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,101 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal.timeline.model; + +import com.redhat.thermostat.client.swing.GraphicsUtils; +import com.redhat.thermostat.client.swing.UIDefaults; +import com.redhat.thermostat.thread.client.common.chart.ChartColors; +import com.redhat.thermostat.thread.client.swing.experimental.components.DataPane; +import com.redhat.thermostat.thread.client.swing.experimental.components.Separator; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.Graphics2D; +import javax.swing.Icon; +import javax.swing.JLabel; +import javax.swing.SwingConstants; + +/** + * + */ +public class LegendPanel extends DataPane { + + public LegendPanel(UIDefaults defaults) { + setBorder(new Separator(defaults, Separator.Side.TOP.TOP, Separator.Type.SOLID)); + setLayout(new FlowLayout(FlowLayout.RIGHT, 10, 6)); + setPreferredSize(new Dimension(getWidth(), 30)); + + for (Thread.State state : Thread.State.values()) { + + Color color = ChartColors.getColor(state); + // no chart is black, it's just the default colour + if (!color.equals(Color.BLACK)) { + JLabel label = new JLabel(new ColorIcon(color), SwingConstants.LEFT); + label.setText(state.toString()); + add(label); + } + } + } + + private class ColorIcon implements Icon { + + private Color color; + private ColorIcon(Color color) { + this.color = color; + } + + @Override + public int getIconHeight() { + return 12; + } + + @Override + public int getIconWidth() { + return 12; + } + + @Override + public void paintIcon(Component c, Graphics g, int x, int y) { + Graphics2D graphics = GraphicsUtils.getInstance().createAAGraphics(g); + graphics.setColor(color); + graphics.fillRect(x, y, getIconWidth(), getIconHeight()); + graphics.dispose(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/timeline/model/RangeChangeEvent.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal.timeline.model; + +import com.redhat.thermostat.common.model.Range; +import java.util.EventObject; + +/** + * + */ +public class RangeChangeEvent extends EventObject { + + private final TimelineModel source; + private final Range<Long> range; + + public RangeChangeEvent(TimelineModel source, Range<Long> range) { + super(source); + this.source = source; + this.range = range; + } + + @Override + public TimelineModel getSource() { + return (TimelineModel) super.getSource(); + } + + public Range<Long> getRange() { + return range; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/timeline/model/RangeChangeListener.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal.timeline.model; + +import java.util.EventListener; + +/** + * + */ +public interface RangeChangeListener extends EventListener { + + public void rangeChanged(RangeChangeEvent event); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/timeline/model/RangedTimelineProbe.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal.timeline.model; + +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.thread.client.common.model.timeline.TimelineProbe; + +/** + * + */ +public class RangedTimelineProbe extends TimelineProbe { + + private long probeEnd; + + public RangedTimelineProbe(TimelineProbe probe, long probeStop) + { + super(probe.getColor(), probe.getState(), probe.getTimeStamp()); + this.probeEnd = probeStop; + } + + public void setProbeEnd(long probeEnd) { + this.probeEnd = probeEnd; + } + + public Range<Long> getRange() { + return new Range<>(getTimeStamp(), probeEnd); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/timeline/model/RatioChangeEvent.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal.timeline.model; + +import java.util.EventObject; + +/** + * + */ +public class RatioChangeEvent extends EventObject { + private final TimelineModel source; + private final double ratio; + + public RatioChangeEvent(TimelineModel source, double ratio) { + super(source); + this.source = source; + this.ratio = ratio; + } + + @Override + public TimelineModel getSource() { + return (TimelineModel) super.getSource(); + } + + public double getRatio() { + return ratio; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/timeline/model/RatioChangeListener.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal.timeline.model; + +import java.util.EventListener; + +/** + * + */ +public interface RatioChangeListener extends EventListener { + public void ratioChanged(RatioChangeEvent event); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/timeline/model/TimelineDateFormatter.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal.timeline.model; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * + */ +public class TimelineDateFormatter { + private static final DateFormat DATE_FORMAT = new SimpleDateFormat("HH:mm:ss.SSS"); + + public static String format(long timeStamp) { + return DATE_FORMAT.format(new Date(timeStamp)); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/internal/timeline/model/TimelineModel.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,129 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal.timeline.model; + +import com.redhat.thermostat.common.model.Range; +import javax.swing.BoundedRangeModel; +import javax.swing.event.EventListenerList; + +/** + * + */ +public class TimelineModel { + + public static final double DEFAULT_RATIO = 1./100.; + + private EventListenerList listenerList; + + private double magnificationRatio; + + private Range<Long> range; + private BoundedRangeModel scrollBarModel; + + private TimelineModel model; + + public TimelineModel() { + this.listenerList = new EventListenerList(); + magnificationRatio = DEFAULT_RATIO; + } + + public Range<Long> getRange() { + return range; + } + + public void setRange(Range<Long> range) { + this.range = range; + fireRangeChangeEvent(); + } + + public void setScrollBarModel(BoundedRangeModel scrollBarModel) { + this.scrollBarModel = scrollBarModel; + } + + public BoundedRangeModel getScrollBarModel() { + return scrollBarModel; + } + + public void addRangeChangeListener(RangeChangeListener listener) { + listenerList.add(RangeChangeListener.class, listener); + } + + public void addRatioChangeListener(RatioChangeListener listener) { + listenerList.add(RatioChangeListener.class, listener); + } + + public void removeRatioChangeListener(RatioChangeListener listener) { + listenerList.remove(RatioChangeListener.class, listener); + } + + public void removeRangeChangeListener(RangeChangeListener listener) { + listenerList.remove(RangeChangeListener.class, listener); + } + + public double getMagnificationRatio() { + return magnificationRatio; + } + + public void setMagnificationRatio(double magnificationRatio) { + this.magnificationRatio = magnificationRatio; + fireRatioChangeEvent(); + } + + private void fireRatioChangeEvent() { + Object[] listeners = listenerList.getListenerList(); + RatioChangeEvent event = + new RatioChangeEvent(this, magnificationRatio); + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == RatioChangeListener.class) { + ((RatioChangeListener) listeners[i + 1]).ratioChanged(event); + } + } + } + + private void fireRangeChangeEvent() { + Object[] listeners = listenerList.getListenerList(); + RangeChangeEvent event = + new RangeChangeEvent(this, + new Range<>(range.getMin(), + range.getMax())); + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == RangeChangeListener.class) { + ((RangeChangeListener) listeners[i + 1]).rangeChanged(event); + } + } + } +}
--- a/thread/client-swing/src/test/java/com/redhat/thermostat/thread/client/swing/impl/SwingLockViewTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,148 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; - -import javax.swing.JFrame; -import javax.swing.SwingUtilities; - -import org.fest.swing.annotation.GUITest; -import org.fest.swing.edt.FailOnThreadViolationRepaintManager; -import org.fest.swing.edt.GuiActionRunner; -import org.fest.swing.edt.GuiTask; -import org.fest.swing.fixture.FrameFixture; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; - -import com.redhat.thermostat.annotations.internal.CacioTest; -import com.redhat.thermostat.thread.model.LockInfo; - -import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner; - -@Category(CacioTest.class) -@RunWith(CacioFESTRunner.class) -public class SwingLockViewTest { - - private JFrame frame; - private FrameFixture frameFixture; - private SwingLockView view; - - @BeforeClass - public static void setupOnce() { - FailOnThreadViolationRepaintManager.install(); - } - - @Before - public void setup() { - GuiActionRunner.execute(new GuiTask() { - - @Override - protected void executeInEDT() throws Throwable { - frame = new JFrame(); - view = new SwingLockView(); - frame.add(view.getUiComponent()); - } - }); - frameFixture = new FrameFixture(frame); - } - - @After - public void tearDown() { - frameFixture.cleanUp(); - frameFixture = null; - } - - @GUITest - @Category(GUITest.class) - @Test - public void verifyInitialValues() { - frameFixture.show(); - - String[][] contents = frameFixture.table(SwingLockView.TABLE_NAME).contents(); - for (int i = 0; i < 18; i++) { - String label = contents[i][0]; - String value = contents[i][1]; - assertFalse(label.contains("LocalizedString")); - assertEquals("0", value); - } - } - - @GUITest - @Category(GUITest.class) - @Test - public void verifyTableIsUpdated() { - frameFixture.show(); - - LockInfo lockData = new LockInfo(System.currentTimeMillis(), "writer", "vm", - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18); - - // incidentally, this also checks for correct handling of calls from non EDT - view.setLatestLockData(lockData); - - String[][] contents = frameFixture.table(SwingLockView.TABLE_NAME).contents(); - for (int i = 0; i < 18; i++) { - String value = contents[i][1]; - assertEquals(String.valueOf(i + 1), value); - } - } - - public static void main(String[] args) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - JFrame mainWindow = new JFrame("mainWindow"); - - SwingLockView view = new SwingLockView(); - mainWindow.add(view.getUiComponent()); - - LockInfo lockData = new LockInfo(System.currentTimeMillis(), "writer", "vm", - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18); - - view.setLatestLockData(lockData); - mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - mainWindow.pack(); - mainWindow.setVisible(true); - } - }); - } -}
--- a/thread/client-swing/src/test/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadViewDemo.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,178 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl; - -import com.redhat.thermostat.client.swing.UIDefaults; -import com.redhat.thermostat.client.ui.Palette; -import com.redhat.thermostat.common.model.Range; -import com.redhat.thermostat.thread.client.common.model.timeline.ThreadInfo; -import com.redhat.thermostat.thread.client.common.model.timeline.TimelineProbe; -import com.redhat.thermostat.thread.client.common.view.ThreadTimelineView; -import com.redhat.thermostat.thread.client.swing.experimental.components.ContentPane; -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.SwingUtilities; -import javax.swing.SwingWorker; -import org.mockito.Mockito; - -import static org.mockito.Mockito.when; - -/** - * - */ -public class SwingThreadViewDemo { - - public static void main(String[] args) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - - UIDefaults defaults = createUIDefaults(); - - ContentPane contentPane = new ContentPane(); - - SwingThreadTimelineView view = new SwingThreadTimelineView(defaults); - JFrame frame = new JFrame(); - frame.add(contentPane); - - contentPane.add(view.getUiComponent()); - - JButton addDate = new JButton("Add Timeline Data"); - - addDate.addActionListener(new DataFiller(view)); - contentPane.add(addDate, BorderLayout.SOUTH); - - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame.setSize(new Dimension(800, 800)); - frame.setVisible(true); - } - }); - } - - private static class DataFiller implements ActionListener { - - private ThreadTimelineView view; - private long startTime; - private long lastUpdate; - - private boolean threadAdded; - private int swap; - private boolean swapped; - - DataFiller(ThreadTimelineView view) { - this.view = view; - startTime = System.currentTimeMillis(); - lastUpdate = startTime; - swap = 0; - } - - @Override - public void actionPerformed(ActionEvent e) { - lastUpdate = System.currentTimeMillis(); - final Range<Long> range = new Range<>(startTime, lastUpdate); - - SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { - @Override - protected Void doInBackground() throws Exception { - - //System.err.println("range: " + (range.getMax() - range.getMin())); - - view.setTotalRange(range); - - if (!threadAdded) { - ThreadInfo info = new ThreadInfo(); - info.setName("test1"); - info.setId(0l); - view.addThread(info); - - info = new ThreadInfo(); - info.setName("test2"); - info.setId(1l); - view.addThread(info); - - threadAdded = true; - - } else { - - Palette color1 = Palette.THERMOSTAT_BLU; - Palette color2 = Palette.THERMOSTAT_RED; - - if (swapped) { - color1 = Palette.THERMOSTAT_RED; - color2 = Palette.THERMOSTAT_BLU; - } - - swap++; - if (swap % 10 == 0) { - swapped = !swapped; - swap = 0; - } - - ThreadInfo info = new ThreadInfo(); - info.setName("test1"); - info.setId(0l); - TimelineProbe probe = new TimelineProbe(color1, "test1", lastUpdate); - view.addProbe(info, probe); - - info = new ThreadInfo(); - info.setName("test2"); - info.setId(1l); - probe = new TimelineProbe(color2, "test2", lastUpdate); - view.addProbe(info, probe); - } - - return null; - } - }; - worker.execute(); - } - } - - private static UIDefaults createUIDefaults() { - UIDefaults defaults = Mockito.mock(UIDefaults.class); - when(defaults.getDefaultFont()).thenReturn(new JLabel().getFont()); - when(defaults.getIconColor()).thenReturn(Palette.EARL_GRAY.getColor()); - when(defaults.getSelectedComponentBGColor()).thenReturn(Palette.ADWAITA_BLU.getColor()); - - return defaults; - } -}
--- a/thread/client-swing/src/test/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadViewDemo2.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,186 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl; - -import com.redhat.thermostat.client.swing.UIDefaults; -import com.redhat.thermostat.client.ui.Palette; -import com.redhat.thermostat.common.model.Range; -import com.redhat.thermostat.thread.client.common.model.timeline.ThreadInfo; -import com.redhat.thermostat.thread.client.common.model.timeline.TimelineProbe; -import com.redhat.thermostat.thread.client.common.view.ThreadTimelineView; -import com.redhat.thermostat.thread.client.swing.experimental.components.ContentPane; -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.SwingUtilities; -import javax.swing.SwingWorker; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * Same as demo 1, except that timelines are always exactly one fixed interval - * apart and probes are added right away. - */ -public class SwingThreadViewDemo2 { - - private static final int INTERVAL = 100; // ms - - public static void main(String[] args) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - - UIDefaults defaults = createUIDefaults(); - - ContentPane contentPane = new ContentPane(); - - SwingThreadTimelineView view = new SwingThreadTimelineView(defaults); - JFrame frame = new JFrame(); - frame.add(contentPane); - - contentPane.add(view.getUiComponent()); - - JButton addDate = new JButton("Add Timeline Data"); - - addDate.addActionListener(new DataFiller(view)); - contentPane.add(addDate, BorderLayout.SOUTH); - - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame.setSize(new Dimension(800, 800)); - frame.setVisible(true); - } - }); - } - - private static class DataFiller implements ActionListener { - - private ThreadTimelineView view; - private long startTime; - private long lastUpdate; - - private boolean threadAdded; - private int swap; - private boolean swapped; - - private int added; - - DataFiller(ThreadTimelineView view) { - this.view = view; - startTime = 0l; - lastUpdate = 0l; - swap = 0; - } - - @Override - public void actionPerformed(ActionEvent e) { - lastUpdate += INTERVAL; - final Range<Long> range = new Range<>(startTime, lastUpdate); - - SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { - @Override - protected Void doInBackground() throws Exception { - -// System.err.println("range: " + (range.getMax() - range.getMin())); - - view.setTotalRange(range); - - if (!threadAdded) { - ThreadInfo info = new ThreadInfo(); - info.setName("test1"); - info.setId(0l); - view.addThread(info); - - info = new ThreadInfo(); - info.setName("test2"); - info.setId(1l); - view.addThread(info); - - threadAdded = true; - - } - - Palette color1 = Palette.THERMOSTAT_BLU; - Palette color2 = Palette.THERMOSTAT_RED; - - if (swapped) { - color1 = Palette.THERMOSTAT_RED; - color2 = Palette.THERMOSTAT_BLU; - } - - swap++; - if (swap % 10 == 0) { - swapped = !swapped; - swap = 0; - } - - ThreadInfo info = new ThreadInfo(); - info.setName("test1"); - info.setId(0l); - TimelineProbe probe = new TimelineProbe(color1, "test1", lastUpdate); - view.addProbe(info, probe); - - info = new ThreadInfo(); - info.setName("test2"); - info.setId(1l); - probe = new TimelineProbe(color2, "test2", lastUpdate); - view.addProbe(info, probe); - - added++; - - // System.err.println("probes added: " + added); - - return null; - } - }; - worker.execute(); - } - } - - private static UIDefaults createUIDefaults() { - UIDefaults defaults = mock(UIDefaults.class); - when(defaults.getDefaultFont()).thenReturn(new JLabel().getFont()); - when(defaults.getIconColor()).thenReturn(Palette.EARL_GRAY.getColor()); - when(defaults.getSelectedComponentBGColor()).thenReturn(Palette.ADWAITA_BLU.getColor()); - - return defaults; - } -}
--- a/thread/client-swing/src/test/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadViewDemo3.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,182 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl; - -import com.redhat.thermostat.client.swing.UIDefaults; -import com.redhat.thermostat.client.ui.Palette; -import com.redhat.thermostat.common.model.Range; -import com.redhat.thermostat.thread.client.common.model.timeline.ThreadInfo; -import com.redhat.thermostat.thread.client.common.model.timeline.TimelineProbe; -import com.redhat.thermostat.thread.client.common.view.ThreadTimelineView; -import com.redhat.thermostat.thread.client.swing.experimental.components.ContentPane; -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.SwingUtilities; -import javax.swing.SwingWorker; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * Same as demo 2, except that it insert 10 minutes worth of timelines. - * Startup time is also configurable. - */ -public class SwingThreadViewDemo3 { - - private static final int INTERVAL = 100; // ms - private static final long STARTUP = 999l; // ms - - public static void main(String[] args) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - - UIDefaults defaults = createUIDefaults(); - - ContentPane contentPane = new ContentPane(); - - SwingThreadTimelineView view = new SwingThreadTimelineView(defaults); - JFrame frame = new JFrame(); - frame.add(contentPane); - - contentPane.add(view.getUiComponent()); - - JButton addDate = new JButton("Add Timeline Data"); - - addDate.addActionListener(new DataFiller(view)); - contentPane.add(addDate, BorderLayout.SOUTH); - - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame.setSize(new Dimension(800, 800)); - frame.setVisible(true); - } - }); - } - - private static class DataFiller implements ActionListener { - - private ThreadTimelineView view; - private long startTime; - private long lastUpdate; - - private boolean threadAdded; - private int swap; - private boolean swapped; - - private int added; - - DataFiller(ThreadTimelineView view) { - this.view = view; - startTime = STARTUP; - lastUpdate = STARTUP; - swap = 0; - } - - @Override - public void actionPerformed(ActionEvent e) { - SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { - @Override - protected Void doInBackground() throws Exception { - for (long l = 0; l < 10_000; l+=INTERVAL) { - lastUpdate += INTERVAL; - final Range<Long> range = new Range<>(startTime, lastUpdate); - view.setTotalRange(range); - - if (!threadAdded) { - ThreadInfo info = new ThreadInfo(); - info.setName("test1"); - info.setId(0l); - view.addThread(info); - - info = new ThreadInfo(); - info.setName("test2"); - info.setId(1l); - view.addThread(info); - - threadAdded = true; - - } - - Palette color1 = Palette.THERMOSTAT_BLU; - Palette color2 = Palette.THERMOSTAT_RED; - - if (swapped) { - color1 = Palette.THERMOSTAT_RED; - color2 = Palette.THERMOSTAT_BLU; - } - - swap++; - if (swap % 10 == 0) { - swapped = !swapped; - swap = 0; - } - - ThreadInfo info = new ThreadInfo(); - info.setName("test1"); - info.setId(0l); - TimelineProbe probe = new TimelineProbe(color1, "test1", lastUpdate); - view.addProbe(info, probe); - - info = new ThreadInfo(); - info.setName("test2"); - info.setId(1l); - probe = new TimelineProbe(color2, "test2", lastUpdate); - view.addProbe(info, probe); - - added++; - } - return null; - } - }; - worker.execute(); - } - } - - private static UIDefaults createUIDefaults() { - UIDefaults defaults = mock(UIDefaults.class); - when(defaults.getDefaultFont()).thenReturn(new JLabel().getFont()); - when(defaults.getIconColor()).thenReturn(Palette.EARL_GRAY.getColor()); - when(defaults.getSelectedComponentBGColor()).thenReturn(Palette.ADWAITA_BLU.getColor()); - - return defaults; - } -}
--- a/thread/client-swing/src/test/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadViewTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,213 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.client.swing.impl; - -import com.redhat.thermostat.annotations.internal.CacioTest; -import com.redhat.thermostat.client.swing.UIDefaults; -import com.redhat.thermostat.shared.locale.Translate; -import com.redhat.thermostat.thread.client.common.locale.LocaleResources; - -import java.awt.Color; -import java.awt.Component; -import java.lang.reflect.InvocationTargetException; -import java.util.Locale; - -import javax.swing.JFrame; - -import com.redhat.thermostat.thread.client.common.view.ThreadView; -import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner; - -import org.fest.swing.annotation.GUITest; -import org.fest.swing.edt.FailOnThreadViolationRepaintManager; -import org.fest.swing.edt.GuiActionRunner; -import org.fest.swing.edt.GuiTask; -import org.fest.swing.fixture.FrameFixture; -import org.fest.swing.fixture.JTabbedPaneFixture; -import org.fest.swing.fixture.JToggleButtonFixture; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -@Category(CacioTest.class) -@RunWith(CacioFESTRunner.class) -public class SwingThreadViewTest { - - private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); - - private SwingThreadView view; - - private JFrame frame; - private FrameFixture frameFixture; - - private static Locale locale; - - private static UIDefaults defaults; - - @BeforeClass - public static void setUpOnce() { - defaults = mock(UIDefaults.class); - when(defaults.getReferenceFieldIconColor()).thenReturn(Color.BLACK); - - FailOnThreadViolationRepaintManager.install(); - locale = Locale.getDefault(); - Locale.setDefault(Locale.US); - } - - @AfterClass - public static void tearDownOnce() { - Locale.setDefault(locale); - } - - @After - public void tearDown() { - frameFixture.cleanUp(); - frameFixture = null; - } - - @Before - public void setUp() { - GuiActionRunner.execute(new GuiTask() { - @Override - protected void executeInEDT() throws Throwable { - view = new SwingThreadView(defaults); - frame = new JFrame(); - frame.add(view.getUiComponent()); - } - }); - frameFixture = new FrameFixture(frame); - } - - @Category(GUITest.class) - @GUITest - @Test - public void verifyThreadCountIsFirstTab() { - frameFixture.show(); - - JTabbedPaneFixture tabPane = frameFixture.tabbedPane("topTabbedPane"); - Component comp = tabPane.component().getComponentAt(0); - assertEquals("count", comp.getName()); - - comp = tabPane.component().getComponentAt(1); - assertEquals("timeline", comp.getName()); - } - - @GUITest - @Test - public void verifyMonitorLabelChange() throws InvocationTargetException, InterruptedException { - frameFixture.show(); - - JToggleButtonFixture togglefixture = frameFixture.toggleButton("recordButton"); - - togglefixture.requireToolTip(t.localize(LocaleResources.START_RECORDING).getContents()); - - togglefixture.click(); - - togglefixture.requireToolTip(t.localize(LocaleResources.STOP_RECORDING).getContents()); - - // now try "programmatically" - - view.setRecording(ThreadView.MonitoringState.STARTED, true); - - togglefixture.requireToolTip(t.localize(LocaleResources.STOP_RECORDING).getContents()); - - view.setRecording(ThreadView.MonitoringState.STOPPED, false); - - togglefixture.requireToolTip(t.localize(LocaleResources.START_RECORDING).getContents()); - } - - @Category(GUITest.class) - @GUITest - @Test - public void verifyToggleButtonIsDisabled() { - frameFixture.show(); - - view.setEnableRecordingControl(false); - - JToggleButtonFixture togglefixture = frameFixture.toggleButton("recordButton"); - togglefixture.requireDisabled(); - } - -// @GUITest -// @Test -// public void verifTableViewLinksToDetailsView() throws InvocationTargetException, InterruptedException { -// -// final boolean listenerCalled[] = new boolean[1]; -// -// ThreadTableBean bean1 = mock(ThreadTableBean.class); -// when(bean1.getName()).thenReturn("mocked bean 1"); -// -// ThreadTableBean bean2 = mock(ThreadTableBean.class); -// when(bean2.getName()).thenReturn("mocked bean 2"); -// -// List<ThreadTableBean> threadList = new ArrayList<>(); -// threadList.add(bean1); -// threadList.add(bean2); -// -// frameFixture.show(); -// -// frameFixture.splitPane("threadMainPanelSplitPane").moveDividerTo(0); -// frameFixture.tabbedPane("bottomTabbedPane").selectTab(0); -// -// final Semaphore sem = new Semaphore(1); -// ThreadTableView tableView = view.createThreadTableView(); -// tableView.addThreadSelectionActionListener(new ActionListener<ThreadTableView.ThreadSelectionAction>() { -// @Override -// public void actionPerformed(ActionEvent<ThreadSelectionAction> actionEvent) { -// listenerCalled[0] = true; -// view.displayThreadDetails((ThreadTableBean) actionEvent.getPayload()); -// sem.release(); -// } -// }); -// -// tableView.display(threadList); -// -// frameFixture.table("threadBeansTable").cell(TableCell.row(1).column(0)).doubleClick(); -// sem.acquire(); -// -// assertTrue(listenerCalled[0]); -// assertEquals(1, frameFixture.tabbedPane("bottomTabbedPane").target.getSelectedIndex()); -// } -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/test/java/com/redhat/thermostat/thread/client/swing/internal/SwingLockViewTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,148 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +import org.fest.swing.annotation.GUITest; +import org.fest.swing.edt.FailOnThreadViolationRepaintManager; +import org.fest.swing.edt.GuiActionRunner; +import org.fest.swing.edt.GuiTask; +import org.fest.swing.fixture.FrameFixture; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; + +import com.redhat.thermostat.annotations.internal.CacioTest; +import com.redhat.thermostat.thread.model.LockInfo; + +import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner; + +@Category(CacioTest.class) +@RunWith(CacioFESTRunner.class) +public class SwingLockViewTest { + + private JFrame frame; + private FrameFixture frameFixture; + private SwingLockView view; + + @BeforeClass + public static void setupOnce() { + FailOnThreadViolationRepaintManager.install(); + } + + @Before + public void setup() { + GuiActionRunner.execute(new GuiTask() { + + @Override + protected void executeInEDT() throws Throwable { + frame = new JFrame(); + view = new SwingLockView(); + frame.add(view.getUiComponent()); + } + }); + frameFixture = new FrameFixture(frame); + } + + @After + public void tearDown() { + frameFixture.cleanUp(); + frameFixture = null; + } + + @GUITest + @Category(GUITest.class) + @Test + public void verifyInitialValues() { + frameFixture.show(); + + String[][] contents = frameFixture.table(SwingLockView.TABLE_NAME).contents(); + for (int i = 0; i < 18; i++) { + String label = contents[i][0]; + String value = contents[i][1]; + assertFalse(label.contains("LocalizedString")); + assertEquals("0", value); + } + } + + @GUITest + @Category(GUITest.class) + @Test + public void verifyTableIsUpdated() { + frameFixture.show(); + + LockInfo lockData = new LockInfo(System.currentTimeMillis(), "writer", "vm", + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18); + + // incidentally, this also checks for correct handling of calls from non EDT + view.setLatestLockData(lockData); + + String[][] contents = frameFixture.table(SwingLockView.TABLE_NAME).contents(); + for (int i = 0; i < 18; i++) { + String value = contents[i][1]; + assertEquals(String.valueOf(i + 1), value); + } + } + + public static void main(String[] args) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + JFrame mainWindow = new JFrame("mainWindow"); + + SwingLockView view = new SwingLockView(); + mainWindow.add(view.getUiComponent()); + + LockInfo lockData = new LockInfo(System.currentTimeMillis(), "writer", "vm", + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18); + + view.setLatestLockData(lockData); + mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + mainWindow.pack(); + mainWindow.setVisible(true); + } + }); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/test/java/com/redhat/thermostat/thread/client/swing/internal/SwingThreadViewDemo.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,181 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal; + +import static org.mockito.Mockito.when; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; + +import org.mockito.Mockito; + +import com.redhat.thermostat.client.swing.UIDefaults; +import com.redhat.thermostat.client.ui.Palette; +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.thread.client.common.model.timeline.ThreadInfo; +import com.redhat.thermostat.thread.client.common.model.timeline.TimelineProbe; +import com.redhat.thermostat.thread.client.common.view.ThreadTimelineView; +import com.redhat.thermostat.thread.client.swing.experimental.components.ContentPane; + +/** + * + */ +public class SwingThreadViewDemo { + + public static void main(String[] args) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + + UIDefaults defaults = createUIDefaults(); + + ContentPane contentPane = new ContentPane(); + + SwingThreadTimelineView view = new SwingThreadTimelineView(defaults); + JFrame frame = new JFrame(); + frame.add(contentPane); + + contentPane.add(view.getUiComponent()); + + JButton addDate = new JButton("Add Timeline Data"); + + addDate.addActionListener(new DataFiller(view)); + contentPane.add(addDate, BorderLayout.SOUTH); + + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setSize(new Dimension(800, 800)); + frame.setVisible(true); + } + }); + } + + private static class DataFiller implements ActionListener { + + private ThreadTimelineView view; + private long startTime; + private long lastUpdate; + + private boolean threadAdded; + private int swap; + private boolean swapped; + + DataFiller(ThreadTimelineView view) { + this.view = view; + startTime = System.currentTimeMillis(); + lastUpdate = startTime; + swap = 0; + } + + @Override + public void actionPerformed(ActionEvent e) { + lastUpdate = System.currentTimeMillis(); + final Range<Long> range = new Range<>(startTime, lastUpdate); + + SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { + @Override + protected Void doInBackground() throws Exception { + + //System.err.println("range: " + (range.getMax() - range.getMin())); + + view.setTotalRange(range); + + if (!threadAdded) { + ThreadInfo info = new ThreadInfo(); + info.setName("test1"); + info.setId(0l); + view.addThread(info); + + info = new ThreadInfo(); + info.setName("test2"); + info.setId(1l); + view.addThread(info); + + threadAdded = true; + + } else { + + Palette color1 = Palette.THERMOSTAT_BLU; + Palette color2 = Palette.THERMOSTAT_RED; + + if (swapped) { + color1 = Palette.THERMOSTAT_RED; + color2 = Palette.THERMOSTAT_BLU; + } + + swap++; + if (swap % 10 == 0) { + swapped = !swapped; + swap = 0; + } + + ThreadInfo info = new ThreadInfo(); + info.setName("test1"); + info.setId(0l); + TimelineProbe probe = new TimelineProbe(color1, "test1", lastUpdate); + view.addProbe(info, probe); + + info = new ThreadInfo(); + info.setName("test2"); + info.setId(1l); + probe = new TimelineProbe(color2, "test2", lastUpdate); + view.addProbe(info, probe); + } + + return null; + } + }; + worker.execute(); + } + } + + private static UIDefaults createUIDefaults() { + UIDefaults defaults = Mockito.mock(UIDefaults.class); + when(defaults.getDefaultFont()).thenReturn(new JLabel().getFont()); + when(defaults.getIconColor()).thenReturn(Palette.EARL_GRAY.getColor()); + when(defaults.getSelectedComponentBGColor()).thenReturn(Palette.ADWAITA_BLU.getColor()); + + return defaults; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/test/java/com/redhat/thermostat/thread/client/swing/internal/SwingThreadViewDemo2.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,188 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; + +import com.redhat.thermostat.client.swing.UIDefaults; +import com.redhat.thermostat.client.ui.Palette; +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.thread.client.common.model.timeline.ThreadInfo; +import com.redhat.thermostat.thread.client.common.model.timeline.TimelineProbe; +import com.redhat.thermostat.thread.client.common.view.ThreadTimelineView; +import com.redhat.thermostat.thread.client.swing.experimental.components.ContentPane; + +/** + * Same as demo 1, except that timelines are always exactly one fixed interval + * apart and probes are added right away. + */ +public class SwingThreadViewDemo2 { + + private static final int INTERVAL = 100; // ms + + public static void main(String[] args) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + + UIDefaults defaults = createUIDefaults(); + + ContentPane contentPane = new ContentPane(); + + SwingThreadTimelineView view = new SwingThreadTimelineView(defaults); + JFrame frame = new JFrame(); + frame.add(contentPane); + + contentPane.add(view.getUiComponent()); + + JButton addDate = new JButton("Add Timeline Data"); + + addDate.addActionListener(new DataFiller(view)); + contentPane.add(addDate, BorderLayout.SOUTH); + + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setSize(new Dimension(800, 800)); + frame.setVisible(true); + } + }); + } + + private static class DataFiller implements ActionListener { + + private ThreadTimelineView view; + private long startTime; + private long lastUpdate; + + private boolean threadAdded; + private int swap; + private boolean swapped; + + private int added; + + DataFiller(ThreadTimelineView view) { + this.view = view; + startTime = 0l; + lastUpdate = 0l; + swap = 0; + } + + @Override + public void actionPerformed(ActionEvent e) { + lastUpdate += INTERVAL; + final Range<Long> range = new Range<>(startTime, lastUpdate); + + SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { + @Override + protected Void doInBackground() throws Exception { + +// System.err.println("range: " + (range.getMax() - range.getMin())); + + view.setTotalRange(range); + + if (!threadAdded) { + ThreadInfo info = new ThreadInfo(); + info.setName("test1"); + info.setId(0l); + view.addThread(info); + + info = new ThreadInfo(); + info.setName("test2"); + info.setId(1l); + view.addThread(info); + + threadAdded = true; + + } + + Palette color1 = Palette.THERMOSTAT_BLU; + Palette color2 = Palette.THERMOSTAT_RED; + + if (swapped) { + color1 = Palette.THERMOSTAT_RED; + color2 = Palette.THERMOSTAT_BLU; + } + + swap++; + if (swap % 10 == 0) { + swapped = !swapped; + swap = 0; + } + + ThreadInfo info = new ThreadInfo(); + info.setName("test1"); + info.setId(0l); + TimelineProbe probe = new TimelineProbe(color1, "test1", lastUpdate); + view.addProbe(info, probe); + + info = new ThreadInfo(); + info.setName("test2"); + info.setId(1l); + probe = new TimelineProbe(color2, "test2", lastUpdate); + view.addProbe(info, probe); + + added++; + + // System.err.println("probes added: " + added); + + return null; + } + }; + worker.execute(); + } + } + + private static UIDefaults createUIDefaults() { + UIDefaults defaults = mock(UIDefaults.class); + when(defaults.getDefaultFont()).thenReturn(new JLabel().getFont()); + when(defaults.getIconColor()).thenReturn(Palette.EARL_GRAY.getColor()); + when(defaults.getSelectedComponentBGColor()).thenReturn(Palette.ADWAITA_BLU.getColor()); + + return defaults; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/test/java/com/redhat/thermostat/thread/client/swing/internal/SwingThreadViewDemo3.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,184 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; + +import com.redhat.thermostat.client.swing.UIDefaults; +import com.redhat.thermostat.client.ui.Palette; +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.thread.client.common.model.timeline.ThreadInfo; +import com.redhat.thermostat.thread.client.common.model.timeline.TimelineProbe; +import com.redhat.thermostat.thread.client.common.view.ThreadTimelineView; +import com.redhat.thermostat.thread.client.swing.experimental.components.ContentPane; + +/** + * Same as demo 2, except that it insert 10 minutes worth of timelines. + * Startup time is also configurable. + */ +public class SwingThreadViewDemo3 { + + private static final int INTERVAL = 100; // ms + private static final long STARTUP = 999l; // ms + + public static void main(String[] args) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + + UIDefaults defaults = createUIDefaults(); + + ContentPane contentPane = new ContentPane(); + + SwingThreadTimelineView view = new SwingThreadTimelineView(defaults); + JFrame frame = new JFrame(); + frame.add(contentPane); + + contentPane.add(view.getUiComponent()); + + JButton addDate = new JButton("Add Timeline Data"); + + addDate.addActionListener(new DataFiller(view)); + contentPane.add(addDate, BorderLayout.SOUTH); + + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setSize(new Dimension(800, 800)); + frame.setVisible(true); + } + }); + } + + private static class DataFiller implements ActionListener { + + private ThreadTimelineView view; + private long startTime; + private long lastUpdate; + + private boolean threadAdded; + private int swap; + private boolean swapped; + + private int added; + + DataFiller(ThreadTimelineView view) { + this.view = view; + startTime = STARTUP; + lastUpdate = STARTUP; + swap = 0; + } + + @Override + public void actionPerformed(ActionEvent e) { + SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { + @Override + protected Void doInBackground() throws Exception { + for (long l = 0; l < 10_000; l+=INTERVAL) { + lastUpdate += INTERVAL; + final Range<Long> range = new Range<>(startTime, lastUpdate); + view.setTotalRange(range); + + if (!threadAdded) { + ThreadInfo info = new ThreadInfo(); + info.setName("test1"); + info.setId(0l); + view.addThread(info); + + info = new ThreadInfo(); + info.setName("test2"); + info.setId(1l); + view.addThread(info); + + threadAdded = true; + + } + + Palette color1 = Palette.THERMOSTAT_BLU; + Palette color2 = Palette.THERMOSTAT_RED; + + if (swapped) { + color1 = Palette.THERMOSTAT_RED; + color2 = Palette.THERMOSTAT_BLU; + } + + swap++; + if (swap % 10 == 0) { + swapped = !swapped; + swap = 0; + } + + ThreadInfo info = new ThreadInfo(); + info.setName("test1"); + info.setId(0l); + TimelineProbe probe = new TimelineProbe(color1, "test1", lastUpdate); + view.addProbe(info, probe); + + info = new ThreadInfo(); + info.setName("test2"); + info.setId(1l); + probe = new TimelineProbe(color2, "test2", lastUpdate); + view.addProbe(info, probe); + + added++; + } + return null; + } + }; + worker.execute(); + } + } + + private static UIDefaults createUIDefaults() { + UIDefaults defaults = mock(UIDefaults.class); + when(defaults.getDefaultFont()).thenReturn(new JLabel().getFont()); + when(defaults.getIconColor()).thenReturn(Palette.EARL_GRAY.getColor()); + when(defaults.getSelectedComponentBGColor()).thenReturn(Palette.ADWAITA_BLU.getColor()); + + return defaults; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-swing/src/test/java/com/redhat/thermostat/thread/client/swing/internal/SwingThreadViewTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,213 @@ +/* + * Copyright 2012-2016 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.thread.client.swing.internal; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.awt.Color; +import java.awt.Component; +import java.lang.reflect.InvocationTargetException; +import java.util.Locale; + +import javax.swing.JFrame; + +import org.fest.swing.annotation.GUITest; +import org.fest.swing.edt.FailOnThreadViolationRepaintManager; +import org.fest.swing.edt.GuiActionRunner; +import org.fest.swing.edt.GuiTask; +import org.fest.swing.fixture.FrameFixture; +import org.fest.swing.fixture.JTabbedPaneFixture; +import org.fest.swing.fixture.JToggleButtonFixture; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; + +import com.redhat.thermostat.annotations.internal.CacioTest; +import com.redhat.thermostat.client.swing.UIDefaults; +import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.thread.client.common.locale.LocaleResources; +import com.redhat.thermostat.thread.client.common.view.ThreadView; + +import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner; + +@Category(CacioTest.class) +@RunWith(CacioFESTRunner.class) +public class SwingThreadViewTest { + + private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); + + private SwingThreadView view; + + private JFrame frame; + private FrameFixture frameFixture; + + private static Locale locale; + + private static UIDefaults defaults; + + @BeforeClass + public static void setUpOnce() { + defaults = mock(UIDefaults.class); + when(defaults.getReferenceFieldIconColor()).thenReturn(Color.BLACK); + + FailOnThreadViolationRepaintManager.install(); + locale = Locale.getDefault(); + Locale.setDefault(Locale.US); + } + + @AfterClass + public static void tearDownOnce() { + Locale.setDefault(locale); + } + + @After + public void tearDown() { + frameFixture.cleanUp(); + frameFixture = null; + } + + @Before + public void setUp() { + GuiActionRunner.execute(new GuiTask() { + @Override + protected void executeInEDT() throws Throwable { + view = new SwingThreadView(defaults); + frame = new JFrame(); + frame.add(view.getUiComponent()); + } + }); + frameFixture = new FrameFixture(frame); + } + + @Category(GUITest.class) + @GUITest + @Test + public void verifyThreadCountIsFirstTab() { + frameFixture.show(); + + JTabbedPaneFixture tabPane = frameFixture.tabbedPane("topTabbedPane"); + Component comp = tabPane.component().getComponentAt(0); + assertEquals("count", comp.getName()); + + comp = tabPane.component().getComponentAt(1); + assertEquals("timeline", comp.getName()); + } + + @GUITest + @Test + public void verifyMonitorLabelChange() throws InvocationTargetException, InterruptedException { + frameFixture.show(); + + JToggleButtonFixture togglefixture = frameFixture.toggleButton("recordButton"); + + togglefixture.requireToolTip(t.localize(LocaleResources.START_RECORDING).getContents()); + + togglefixture.click(); + + togglefixture.requireToolTip(t.localize(LocaleResources.STOP_RECORDING).getContents()); + + // now try "programmatically" + + view.setRecording(ThreadView.MonitoringState.STARTED, true); + + togglefixture.requireToolTip(t.localize(LocaleResources.STOP_RECORDING).getContents()); + + view.setRecording(ThreadView.MonitoringState.STOPPED, false); + + togglefixture.requireToolTip(t.localize(LocaleResources.START_RECORDING).getContents()); + } + + @Category(GUITest.class) + @GUITest + @Test + public void verifyToggleButtonIsDisabled() { + frameFixture.show(); + + view.setEnableRecordingControl(false); + + JToggleButtonFixture togglefixture = frameFixture.toggleButton("recordButton"); + togglefixture.requireDisabled(); + } + +// @GUITest +// @Test +// public void verifTableViewLinksToDetailsView() throws InvocationTargetException, InterruptedException { +// +// final boolean listenerCalled[] = new boolean[1]; +// +// ThreadTableBean bean1 = mock(ThreadTableBean.class); +// when(bean1.getName()).thenReturn("mocked bean 1"); +// +// ThreadTableBean bean2 = mock(ThreadTableBean.class); +// when(bean2.getName()).thenReturn("mocked bean 2"); +// +// List<ThreadTableBean> threadList = new ArrayList<>(); +// threadList.add(bean1); +// threadList.add(bean2); +// +// frameFixture.show(); +// +// frameFixture.splitPane("threadMainPanelSplitPane").moveDividerTo(0); +// frameFixture.tabbedPane("bottomTabbedPane").selectTab(0); +// +// final Semaphore sem = new Semaphore(1); +// ThreadTableView tableView = view.createThreadTableView(); +// tableView.addThreadSelectionActionListener(new ActionListener<ThreadTableView.ThreadSelectionAction>() { +// @Override +// public void actionPerformed(ActionEvent<ThreadSelectionAction> actionEvent) { +// listenerCalled[0] = true; +// view.displayThreadDetails((ThreadTableBean) actionEvent.getPayload()); +// sem.release(); +// } +// }); +// +// tableView.display(threadList); +// +// frameFixture.table("threadBeansTable").cell(TableCell.row(1).column(0)).doubleClick(); +// sem.acquire(); +// +// assertTrue(listenerCalled[0]); +// assertEquals(1, frameFixture.tabbedPane("bottomTabbedPane").target.getSelectedIndex()); +// } +} +
--- a/thread/collector/pom.xml Wed Apr 06 14:52:26 2016 +0200 +++ b/thread/collector/pom.xml Fri Apr 08 13:18:48 2016 +0200 @@ -120,8 +120,8 @@ </Export-Package> <Private-Package> com.redhat.thermostat.thread.common.osgi, - com.redhat.thermostat.thread.dao.impl, - com.redhat.thermostat.thread.dao.impl.statement, + com.redhat.thermostat.thread.dao.internal, + com.redhat.thermostat.thread.dao.internal.statement, </Private-Package> <!-- Do not autogenerate uses clauses in Manifests --> <_nouses>true</_nouses>
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/common/osgi/Activator.java Wed Apr 06 14:52:26 2016 +0200 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/common/osgi/Activator.java Fri Apr 08 13:18:48 2016 +0200 @@ -48,8 +48,8 @@ import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.thread.dao.LockInfoDao; import com.redhat.thermostat.thread.dao.ThreadDao; -import com.redhat.thermostat.thread.dao.impl.LockInfoDaoImpl; -import com.redhat.thermostat.thread.dao.impl.ThreadDaoImpl; +import com.redhat.thermostat.thread.dao.internal.LockInfoDaoImpl; +import com.redhat.thermostat.thread.dao.internal.ThreadDaoImpl; public class Activator implements BundleActivator {
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/ThreadDao.java Wed Apr 06 14:52:26 2016 +0200 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/ThreadDao.java Fri Apr 08 13:18:48 2016 +0200 @@ -41,7 +41,7 @@ import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.VmRef; import com.redhat.thermostat.storage.core.experimental.statement.ResultHandler; -import com.redhat.thermostat.thread.dao.impl.ThreadDaoKeys; +import com.redhat.thermostat.thread.dao.internal.ThreadDaoKeys; import com.redhat.thermostat.thread.model.SessionID; import com.redhat.thermostat.thread.model.ThreadContentionSample; import com.redhat.thermostat.thread.model.ThreadHarvestingStatus;
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/LockInfoDaoCategoryRegistration.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl; - -import java.util.HashSet; -import java.util.Set; - -import com.redhat.thermostat.storage.core.auth.CategoryRegistration; -import com.redhat.thermostat.thread.dao.LockInfoDao; - -public class LockInfoDaoCategoryRegistration implements CategoryRegistration { - - @Override - public Set<String> getCategoryNames() { - Set<String> set = new HashSet<>(); - set.add(LockInfoDao.LOCK_INFO_CATEGORY.getName()); - return set; - } - -}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/LockInfoDaoImpl.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl; - -import java.util.List; -import java.util.logging.Logger; - -import com.redhat.thermostat.common.model.Range; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.core.PreparedStatement; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.VmBoundaryPojoGetter; -import com.redhat.thermostat.storage.core.VmRef; -import com.redhat.thermostat.storage.core.VmTimeIntervalPojoListGetter; -import com.redhat.thermostat.storage.dao.AbstractDao; -import com.redhat.thermostat.storage.dao.AbstractDaoStatement; -import com.redhat.thermostat.thread.dao.LockInfoDao; -import com.redhat.thermostat.thread.model.LockInfo; - -public class LockInfoDaoImpl extends AbstractDao implements LockInfoDao { - - private static final Logger logger = LoggingUtils.getLogger(LockInfoDaoImpl.class); - - static final String ADD_LOCK_INFO = "ADD " + LOCK_INFO_CATEGORY.getName() + - " SET '" + Key.AGENT_ID.getName() + "' = ?s , " + - "'" + Key.VM_ID.getName() + "' = ?s , " + - "'" + Key.TIMESTAMP.getName() + "' = ?l , " + - "'" + CONTENDED_LOCK_ATTEMPTS_KEY.getName() + "' = ?l , " + - "'" + DEFLATIONS_KEY.getName() + "' = ?l , " + - "'" + EMPTY_NOTIFICATIONS_KEY.getName() + "' = ?l , " + - "'" + FAILED_SPINS_KEY.getName() + "' = ?l , " + - "'" + FUTILE_WAKEUPS_KEY.getName() + "' = ?l , " + - "'" + INFLATIONS_KEY.getName() + "' = ?l , " + - "'" + MONITORS_EXTANT_KEY.getName() + "' = ?l , " + - "'" + MONITORS_IN_CIRCULATION_KEY.getName() + "' = ?l , " + - "'" + MONITORS_SCAVENGED_KEY.getName() + "' = ?l , " + - "'" + NOTIFICATIONS_KEY.getName() + "' = ?l , " + - "'" + PARKS_KEY.getName() + "' = ?l , " + - "'" + PRIVATE_A_KEY.getName() + "' = ?l , " + - "'" + PRIVATE_B_KEY.getName() + "' = ?l , " + - "'" + SLOW_ENTER_KEY.getName() + "' = ?l , " + - "'" + SLOW_EXIT_KEY.getName() + "' = ?l , " + - "'" + SLOW_NOTIFY_KEY.getName() + "' = ?l , " + - "'" + SLOW_NOTIFY_ALL_KEY.getName() + "' = ?l , " + - "'" + SUCCESSFUL_SPINS_KEY.getName() + "' = ?l"; - - private final Storage storage; - - private final VmBoundaryPojoGetter<LockInfo> boundaryGetter; - - private VmTimeIntervalPojoListGetter<LockInfo> intervalGetter; - - public LockInfoDaoImpl(Storage storage) { - this.storage = storage; - storage.registerCategory(LOCK_INFO_CATEGORY); - - boundaryGetter = new VmBoundaryPojoGetter<>(storage, LOCK_INFO_CATEGORY); - intervalGetter = new VmTimeIntervalPojoListGetter<>(storage, LOCK_INFO_CATEGORY); - } - - @Override - public void saveLockInfo(final LockInfo info) { - executeStatement(new AbstractDaoStatement<LockInfo>(storage, LOCK_INFO_CATEGORY, ADD_LOCK_INFO) { - @Override - public PreparedStatement<LockInfo> customize(PreparedStatement<LockInfo> preparedStatement) { - preparedStatement.setString(0, info.getAgentId()); - preparedStatement.setString(1, info.getVmId()); - preparedStatement.setLong(2, info.getTimeStamp()); - preparedStatement.setLong(3, info.getContendedLockAttempts()); - preparedStatement.setLong(4, info.getDeflations()); - preparedStatement.setLong(5, info.getEmptyNotifications()); - preparedStatement.setLong(6, info.getFailedSpins()); - preparedStatement.setLong(7, info.getFutileWakeups()); - preparedStatement.setLong(8, info.getInflations()); - preparedStatement.setLong(9, info.getMonExtant()); - preparedStatement.setLong(10, info.getMonInCirculation()); - preparedStatement.setLong(11, info.getMonScavenged()); - preparedStatement.setLong(12, info.getNotifications()); - preparedStatement.setLong(13, info.getParks()); - preparedStatement.setLong(14, info.getPrivateA()); - preparedStatement.setLong(15, info.getPrivateB()); - preparedStatement.setLong(16, info.getSlowEnter()); - preparedStatement.setLong(17, info.getSlowExit()); - preparedStatement.setLong(18, info.getSlowNotify()); - preparedStatement.setLong(19, info.getSlowNotifyAll()); - preparedStatement.setLong(20, info.getSuccessfulSpins()); - - return preparedStatement; - } - }); - } - - @Override - public List<LockInfo> getLockInfo(VmRef ref, Range<Long> range) { - return intervalGetter.getLatest(ref, range.getMin(), range.getMax()); - } - - @Override - public LockInfo getLatestLockInfo(VmRef ref) { - return boundaryGetter.getNewestStat(ref); - } - - @Override - protected Logger getLogger() { - return logger; - } - -}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/LockInfoDaoImplStatementDescriptorRegistration.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl; - -import java.util.HashSet; -import java.util.Set; - -import com.redhat.thermostat.storage.core.VmBoundaryPojoGetter; -import com.redhat.thermostat.storage.core.VmTimeIntervalPojoListGetter; -import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; -import com.redhat.thermostat.thread.dao.LockInfoDao; - -public class LockInfoDaoImplStatementDescriptorRegistration - implements StatementDescriptorRegistration { - - @Override - public Set<String> getStatementDescriptors() { - Set<String> set = new HashSet<>(); - - set.add(LockInfoDaoImpl.ADD_LOCK_INFO); - - String latestStatDescriptor = String.format( - VmBoundaryPojoGetter.DESC_NEWEST_VM_STAT, - LockInfoDao.LOCK_INFO_CATEGORY.getName()); - - set.add(latestStatDescriptor); - - String rangeStatDescriptor = String.format( - VmTimeIntervalPojoListGetter.VM_INTERVAL_QUERY_FORMAT, - LockInfoDao.LOCK_INFO_CATEGORY.getName()); - set.add(rangeStatDescriptor); - - return set; - } - -}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOCategoryRegistration.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl; - -import java.util.HashSet; -import java.util.Set; - -import com.redhat.thermostat.storage.core.auth.CategoryRegistration; -import com.redhat.thermostat.thread.dao.ThreadDao; - -/** - * Registers the category used by this maven module. The web storage - * endpoint only allows categories to be registered which it knows of - * ahead of time. - * - */ -public class ThreadDAOCategoryRegistration implements CategoryRegistration { - - @Override - public Set<String> getCategoryNames() { - Set<String> categories = new HashSet<>(); - - categories.add(ThreadDao.DEADLOCK_INFO.getName()); - categories.add(ThreadDao.THREAD_HARVESTING_STATUS.getName()); - categories.add(ThreadDao.THREAD_CONTENTION_SAMPLE.getName()); - - ThreadDaoCategories.register(categories); - - return categories; - } -} -
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoCategories.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl; - -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.experimental.statement.CategoryBuilder; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.thread.model.ThreadSession; -import com.redhat.thermostat.thread.model.ThreadState; -import com.redhat.thermostat.thread.model.ThreadSummary; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.logging.Logger; - -/** - * - */ -public class ThreadDaoCategories { - - private static final Logger logger = LoggingUtils.getLogger(ThreadDaoCategories.class); - - public static class Categories { - public static final String SUMMARY = "vm-thread-summary"; - public static final String SESSION = "vm-thread-session"; - public static final String STATE = "vm-thread-state"; - - } - - static final List<Class<? extends Pojo>> BEANS = new ArrayList<>(); - static { - BEANS.add(ThreadSummary.class); - BEANS.add(ThreadSession.class); - BEANS.add(ThreadState.class); - } - - public static void register(Collection<String> collection) { - for (Class<? extends Pojo> beanClass: BEANS) { - Category<? extends Pojo> category = new CategoryBuilder(beanClass).build(); - collection.add(category.getName()); - } - } - - public static void register(Storage storage) { - for (Class<? extends Pojo> beanClass: BEANS) { - Category<? extends Pojo> category = new CategoryBuilder(beanClass).build(); - storage.registerCategory(category); - } - } -}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,355 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl; - -import com.redhat.thermostat.common.model.Range; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.Cursor; -import com.redhat.thermostat.storage.core.DescriptorParsingException; -import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.core.PreparedStatement; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.core.StatementExecutionException; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.VmRef; -import com.redhat.thermostat.storage.core.experimental.statement.BeanAdapter; -import com.redhat.thermostat.storage.core.experimental.statement.BeanAdapterBuilder; -import com.redhat.thermostat.storage.core.Id; -import com.redhat.thermostat.storage.core.experimental.statement.Query; -import com.redhat.thermostat.storage.core.experimental.statement.QueryValues; -import com.redhat.thermostat.storage.core.experimental.statement.ResultHandler; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.thread.dao.ThreadDao; -import com.redhat.thermostat.thread.dao.impl.statement.SessionQueries; -import com.redhat.thermostat.thread.dao.impl.statement.StateQueries; -import com.redhat.thermostat.thread.dao.impl.statement.SummaryQuery; -import com.redhat.thermostat.thread.model.SessionID; -import com.redhat.thermostat.thread.model.ThreadHarvestingStatus; -import com.redhat.thermostat.thread.model.ThreadSession; -import com.redhat.thermostat.thread.model.ThreadState; -import com.redhat.thermostat.thread.model.ThreadSummary; -import com.redhat.thermostat.thread.model.VmDeadLockData; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static com.redhat.thermostat.common.utils.IteratorUtils.head; - -public class ThreadDaoImpl implements ThreadDao { - - private static final Logger logger = LoggingUtils.getLogger(ThreadDaoImpl.class); - - static final BeanAdapter<ThreadSummary> ThreadSummaryAdapter = new BeanAdapterBuilder<>(ThreadSummary.class, new SummaryQuery()).build(); - static final BeanAdapter<ThreadSession> ThreadSessionAdapter = new BeanAdapterBuilder<>(ThreadSession.class, SessionQueries.asList()).build(); - static final BeanAdapter<ThreadState> ThreadStateAdapter = new BeanAdapterBuilder<>(ThreadState.class, StateQueries.asList()).build(); - - static final String QUERY_LATEST_HARVESTING_STATUS = "QUERY " - + THREAD_HARVESTING_STATUS.getName() + " WHERE '" - + Key.AGENT_ID.getName() + "' = ?s AND '" - + Key.VM_ID.getName() + "' = ?s SORT '" - + Key.TIMESTAMP.getName() + "' DSC LIMIT 1"; - - static final String QUERY_LATEST_DEADLOCK_INFO = "QUERY " - + DEADLOCK_INFO.getName() + " WHERE '" - + Key.AGENT_ID.getName() + "' = ?s AND '" - + Key.VM_ID.getName() + "' = ?s SORT '" - + Key.TIMESTAMP.getName() + "' DSC LIMIT 1"; - - static final String DESC_ADD_THREAD_HARVESTING_STATUS = "ADD " + THREAD_HARVESTING_STATUS.getName() + - " SET '" + Key.AGENT_ID.getName() + "' = ?s , " + - "'" + Key.VM_ID.getName() + "' = ?s , " + - "'" + Key.TIMESTAMP.getName() + "' = ?l , " + - "'" + HARVESTING_STATUS_KEY.getName() + "' = ?b"; - - static final String DESC_ADD_THREAD_DEADLOCK_DATA = "ADD " + DEADLOCK_INFO.getName() + - " SET '" + Key.AGENT_ID.getName() + "' = ?s , " + - "'" + Key.VM_ID.getName() + "' = ?s , " + - "'" + Key.TIMESTAMP.getName() + "' = ?l , " + - "'" + DEADLOCK_DESCRIPTION_KEY.getName() + "' = ?s"; - - - static final String ADD_CONTENTION_SAMPLE = - "ADD " + THREAD_CONTENTION_SAMPLE.getName() + " " + - "SET '" + Key.AGENT_ID.getName() + "' = ?s , " + - "'" + Key.VM_ID.getName() + "' = ?s , " + - "'" + THREAD_CONTENTION_BLOCKED_COUNT_KEY.getName() + "' = ?l , " + - "'" + THREAD_CONTENTION_BLOCKED_TIME_KEY.getName() + "' = ?l , " + - "'" + THREAD_CONTENTION_WAITED_COUNT_KEY.getName() + "' = ?l , " + - "'" + THREAD_CONTENTION_WAITED_TIME_KEY.getName() + "' = ?l , " + - "'" + ThreadDaoKeys.THREAD_HEADER_UUID.getName() + "' = ?s , " + - "'" + Key.TIMESTAMP.getName() + "' = ?l"; - - static final String GET_LATEST_CONTENTION_SAMPLE= "QUERY " - + THREAD_CONTENTION_SAMPLE.getName() + " WHERE '" - + ThreadDaoKeys.THREAD_HEADER_UUID.getName() + "' = ?s SORT '" - + Key.TIMESTAMP.getName() + "' DSC LIMIT 1"; - - private Storage storage; - - public ThreadDaoImpl(Storage storage) { - this.storage = storage; - - ThreadDaoCategories.register(storage); - - storage.registerCategory(THREAD_HARVESTING_STATUS); - storage.registerCategory(THREAD_CONTENTION_SAMPLE); - - storage.registerCategory(DEADLOCK_INFO); - } - - @Override - public void saveSummary(ThreadSummary summary) { - try { - ThreadSummaryAdapter.insert(summary, storage); - - } catch (StatementExecutionException e) { - logger.log(Level.SEVERE, "Exception saving summary: " + summary, e); - } - } - - @Override - public void addThreadState(ThreadState thread) { - try { - ThreadStateAdapter.insert(thread, storage); - - } catch (StatementExecutionException e) { - logger.log(Level.SEVERE, "Exception saving thread state: " + thread, e); - } - } - - @Override - public void getThreadStates(VmRef ref, SessionID session, - final ResultHandler<ThreadState> handler, - Range<Long> range, int limit, Sort order) - { - Id id = order.equals(Sort.ASCENDING) ? StateQueries.getAscending : - StateQueries.getDescending; - - Query<ThreadState> query = ThreadStateAdapter.getQuery(id); - - QueryValues values = query.createValues(); - values.set(StateQueries.CriteriaId.vmId, ref.getVmId()); - values.set(StateQueries.CriteriaId.agentId, ref.getHostRef().getAgentId()); - values.set(StateQueries.CriteriaId.sessionID, session.get()); - - values.set(StateQueries.CriteriaId.timeStampGEQ, range.getMin()); - values.set(StateQueries.CriteriaId.timeStampLEQ, range.getMax()); - values.set(StateQueries.CriteriaId.limit, limit); - - try { - ThreadStateAdapter.query(values, handler, storage); - - } catch (StatementExecutionException e) { - logger.log(Level.SEVERE, "Exception retrieving thread summary", e); - } - } - - @Override - public List<ThreadSummary> getSummary(VmRef ref, Range<Long> range, int limit) { - final List<ThreadSummary> results = new ArrayList<>(); - - Query<ThreadSummary> query = ThreadSummaryAdapter.getQuery(SummaryQuery.id); - - QueryValues values = query.createValues(); - values.set(SummaryQuery.CriteriaId.vmId, ref.getVmId()); - values.set(SummaryQuery.CriteriaId.agentId, ref.getHostRef().getAgentId()); - - values.set(SummaryQuery.CriteriaId.timeStampGEQ, range.getMin()); - values.set(SummaryQuery.CriteriaId.timeStampLEQ, range.getMax()); - values.set(SummaryQuery.CriteriaId.limit, limit); - - try { - ThreadSummaryAdapter.query(values, new ResultHandler<ThreadSummary>() { - @Override - public boolean onResult(ThreadSummary result) { - results.add(result); - return true; - } - }, storage); - - } catch (StatementExecutionException e) { - logger.log(Level.SEVERE, "Exception retrieving thread summary", e); - } - - return results; - } - - @Override - public List<ThreadSession> getSessions(VmRef ref, Range<Long> range, - int limit, Sort order) - { - final List<ThreadSession> results = new ArrayList<>(); - - Id id = order.equals(Sort.ASCENDING) ? SessionQueries.getRangeAscending : - SessionQueries.getRangeDescending; - - Query<ThreadSession> query = ThreadSessionAdapter.getQuery(id); - - QueryValues values = query.createValues(); - values.set(SessionQueries.CriteriaId.vmId, ref.getVmId()); - values.set(SessionQueries.CriteriaId.agentId, ref.getHostRef().getAgentId()); - - values.set(SessionQueries.CriteriaId.timeStampGEQ, range.getMin()); - values.set(SessionQueries.CriteriaId.timeStampLEQ, range.getMax()); - values.set(SessionQueries.CriteriaId.limit, limit); - - try { - ThreadSessionAdapter.query(values, new ResultHandler<ThreadSession>() { - @Override - public boolean onResult(ThreadSession result) { - results.add(result); - return true; - } - }, storage); - - } catch (StatementExecutionException e) { - logger.log(Level.SEVERE, "Exception retrieving thread session", e); - } - - return results; - } - - public void saveSession(ThreadSession session) { - try { - ThreadSessionAdapter.insert(session, storage); - - } catch (StatementExecutionException e) { - logger.log(Level.SEVERE, "Exception saving session: " + session, e); - } - } - - @Override - public void saveHarvestingStatus(ThreadHarvestingStatus status) { - StatementDescriptor<ThreadHarvestingStatus> desc = new StatementDescriptor<>(THREAD_HARVESTING_STATUS, DESC_ADD_THREAD_HARVESTING_STATUS); - PreparedStatement<ThreadHarvestingStatus> prepared; - try { - prepared = storage.prepareStatement(desc); - prepared.setString(0, status.getAgentId()); - prepared.setString(1, status.getVmId()); - prepared.setLong(2, status.getTimeStamp()); - prepared.setBoolean(3, status.isHarvesting()); - prepared.execute(); - } catch (DescriptorParsingException e) { - logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e); - } catch (StatementExecutionException e) { - logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e); - } - } - - @Override - public ThreadHarvestingStatus getLatestHarvestingStatus(VmRef vm) { - PreparedStatement<ThreadHarvestingStatus> stmt = prepareQuery(THREAD_HARVESTING_STATUS, - QUERY_LATEST_HARVESTING_STATUS, vm); - if (stmt == null) { - return null; - } - - return getFirstResult(stmt); - } - - @Override - public VmDeadLockData loadLatestDeadLockStatus(VmRef ref) { - PreparedStatement<VmDeadLockData> stmt = prepareQuery(DEADLOCK_INFO, QUERY_LATEST_DEADLOCK_INFO, ref); - if (stmt == null) { - return null; - } - - return getFirstResult(stmt); - } - - @Override - public void saveDeadLockStatus(VmDeadLockData deadLockInfo) { - StatementDescriptor<VmDeadLockData> desc = new StatementDescriptor<>(DEADLOCK_INFO, DESC_ADD_THREAD_DEADLOCK_DATA); - PreparedStatement<VmDeadLockData> prepared; - try { - prepared = storage.prepareStatement(desc); - prepared.setString(0, deadLockInfo.getAgentId()); - prepared.setString(1, deadLockInfo.getVmId()); - prepared.setLong(2, deadLockInfo.getTimeStamp()); - prepared.setString(3, deadLockInfo.getDeadLockDescription()); - prepared.execute(); - } catch (DescriptorParsingException e) { - logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e); - } catch (StatementExecutionException e) { - logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e); - } - } - - - /**************************************************************************/ - - private <T extends Pojo> PreparedStatement<T> prepareQuery(Category<T> category, String query, VmRef ref) { - return prepareQuery(category, query, ref, null, null); - } - - private <T extends Pojo> PreparedStatement<T> prepareQuery(Category<T> category, String query, VmRef ref, Long since, Long to) { - StatementDescriptor<T> desc = new StatementDescriptor<>(category, query); - PreparedStatement<T> stmt = null; - try { - stmt = storage.prepareStatement(desc); - stmt.setString(0, ref.getHostRef().getAgentId()); - stmt.setString(1, ref.getVmId()); - // assume: the format of the query is such that 2nd and 3rd arguments (if any) are longs - if (since != null) { - stmt.setLong(2, since); - } - if (to != null) { - stmt.setLong(3, to); - } - } catch (DescriptorParsingException e) { - // should not happen, but if it *does* happen, at least log it - logger.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e); - } - return stmt; - } - - private <T extends Pojo> T getFirstResult(PreparedStatement<T> stmt) { - Cursor<T> cursor; - try { - cursor = stmt.executeQuery(); - } catch (StatementExecutionException e) { - // should not happen, but if it *does* happen, at least log it - logger.log(Level.SEVERE, "Executing query '" + stmt + "' failed!", e); - return null; - } - - return head(cursor); - } -} -
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplStatementDescriptorRegistration.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl; - -import java.util.HashSet; -import java.util.Set; - -import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; - -/** - * Registers prepared queries issued by this maven module via - * via {@link ThreadDaoImpl}. - * - */ -public class ThreadDaoImplStatementDescriptorRegistration implements - StatementDescriptorRegistration { - - private final Set<String> descs; - - public ThreadDaoImplStatementDescriptorRegistration() { - descs = new HashSet<>(); - descs.add(ThreadDaoImpl.QUERY_LATEST_DEADLOCK_INFO); - descs.add(ThreadDaoImpl.QUERY_LATEST_HARVESTING_STATUS); - - // TODO: this needs to go in an helper class - descs.addAll(ThreadDaoImpl.ThreadSummaryAdapter.describeStatements()); - descs.addAll(ThreadDaoImpl.ThreadSessionAdapter.describeStatements()); - descs.addAll(ThreadDaoImpl.ThreadStateAdapter.describeStatements()); - - descs.add(ThreadDaoImpl.DESC_ADD_THREAD_DEADLOCK_DATA); - descs.add(ThreadDaoImpl.DESC_ADD_THREAD_HARVESTING_STATUS); - descs.add(ThreadDaoImpl.ADD_CONTENTION_SAMPLE); - descs.add(ThreadDaoImpl.GET_LATEST_CONTENTION_SAMPLE); - } - - @Override - public Set<String> getStatementDescriptors() { - return descs; - } - -} -
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoKeys.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl; - -import com.redhat.thermostat.storage.core.Key; - -/** - * - */ -public class ThreadDaoKeys { - - public static final Key<String> THREAD_HEADER_UUID = new Key<String>("referenceID"); -}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/SessionQueries.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl.statement; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import com.redhat.thermostat.storage.core.Id; -import com.redhat.thermostat.storage.core.experimental.statement.FieldDescriptor; -import com.redhat.thermostat.storage.core.experimental.statement.LimitCriterion; -import com.redhat.thermostat.storage.core.experimental.statement.Query; -import com.redhat.thermostat.storage.core.experimental.statement.SortCriterion; -import com.redhat.thermostat.storage.core.experimental.statement.StatementUtils; -import com.redhat.thermostat.storage.core.experimental.statement.TypeMapper; -import com.redhat.thermostat.storage.core.experimental.statement.WhereCriterion; -import com.redhat.thermostat.thread.model.ThreadSession; - -/** - * - */ -public class SessionQueries { - - public static final Id getRangeAscending = new Id("SessionQueries::getRangeAscending"); - public static final Id getRangeDescending = new Id("SessionQueries::getRangeDescending"); - - public static class CriteriaId { - public static final Id vmId = new Id("vmId"); - public static final Id agentId = new Id("agentId"); - public static final Id timeStampGEQ = new Id("timeStampGEQ"); - public static final Id timeStampLEQ = new Id("timeStampLEQ"); - public static final Id limit = new Id("limit"); - } - - private static class GetDescending extends Query<ThreadSession> { - @Override - protected void describe(Criteria criteria) { - List<FieldDescriptor> descriptors = StatementUtils.createDescriptors(ThreadSession.class); - final Map<String, FieldDescriptor> map = StatementUtils.createDescriptorMap(descriptors); - - criteria.add(new WhereCriterion(CriteriaId.vmId, map.get("vmId"), - TypeMapper.Criteria.Equal)); - criteria.add(new WhereCriterion(CriteriaId.agentId, map.get("agentId"), - TypeMapper.Criteria.Equal)); - - criteria.add(new WhereCriterion(CriteriaId.timeStampGEQ, map.get("timeStamp"), - TypeMapper.Criteria.GreaterEqual)); - criteria.add(new WhereCriterion(CriteriaId.timeStampLEQ, map.get("timeStamp"), - TypeMapper.Criteria.LessEqual)); - - criteria.add(new SortCriterion(map.get("timeStamp"), TypeMapper.Sort.Descending)); - criteria.add(new LimitCriterion(CriteriaId.limit)); - } - - @Override - public Id getId() { - return getRangeDescending; - } - } - - private static class GetAscending extends Query<ThreadSession> { - @Override - protected void describe(Criteria criteria) { - List<FieldDescriptor> descriptors = StatementUtils.createDescriptors(ThreadSession.class); - final Map<String, FieldDescriptor> map = StatementUtils.createDescriptorMap(descriptors); - - criteria.add(new WhereCriterion(CriteriaId.vmId, map.get("vmId"), - TypeMapper.Criteria.Equal)); - criteria.add(new WhereCriterion(CriteriaId.agentId, map.get("agentId"), - TypeMapper.Criteria.Equal)); - - criteria.add(new WhereCriterion(CriteriaId.timeStampGEQ, map.get("timeStamp"), - TypeMapper.Criteria.GreaterEqual)); - criteria.add(new WhereCriterion(CriteriaId.timeStampLEQ, map.get("timeStamp"), - TypeMapper.Criteria.LessEqual)); - - criteria.add(new SortCriterion(map.get("timeStamp"), TypeMapper.Sort.Ascending)); - criteria.add(new LimitCriterion(CriteriaId.limit)); - } - - @Override - public Id getId() { - return getRangeAscending; - } - } - - private static final List<Query<ThreadSession>> queries = new ArrayList<>(); - static { - queries.add(new GetDescending()); - queries.add(new GetAscending()); - } - - public static List<Query<ThreadSession>> asList() { - return Collections.unmodifiableList(queries); - } -}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/StateQueries.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl.statement; - -import com.redhat.thermostat.storage.core.experimental.statement.FieldDescriptor; -import com.redhat.thermostat.storage.core.Id; -import com.redhat.thermostat.storage.core.experimental.statement.LimitCriterion; -import com.redhat.thermostat.storage.core.experimental.statement.Query; -import com.redhat.thermostat.storage.core.experimental.statement.SortCriterion; -import com.redhat.thermostat.storage.core.experimental.statement.StatementUtils; -import com.redhat.thermostat.storage.core.experimental.statement.TypeMapper; -import com.redhat.thermostat.storage.core.experimental.statement.WhereCriterion; -import com.redhat.thermostat.thread.model.ThreadState; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * - */ -public class StateQueries { - - public static final Id getAscending = new Id("StateQueries::getRangeAscending"); - public static final Id getDescending = new Id("StateQueries::getRangeDescending"); - - public static class CriteriaId { - public static final Id vmId = new Id("vmId"); - public static final Id agentId = new Id("agentId"); - public static final Id timeStampGEQ = new Id("timeStampGEQ"); - public static final Id timeStampLEQ = new Id("timeStampLEQ"); - public static final Id sessionID = new Id("sessionID"); - public static final Id limit = new Id("limit"); - } - - private static class GetDescending extends Query<ThreadState> { - @Override - protected void describe(Criteria criteria) { - List<FieldDescriptor> descriptors = StatementUtils.createDescriptors(ThreadState.class); - final Map<String, FieldDescriptor> map = StatementUtils.createDescriptorMap(descriptors); - - criteria.add(new WhereCriterion(CriteriaId.vmId, map.get("vmId"), - TypeMapper.Criteria.Equal)); - criteria.add(new WhereCriterion(CriteriaId.agentId, map.get("agentId"), - TypeMapper.Criteria.Equal)); - criteria.add(new WhereCriterion(CriteriaId.timeStampGEQ, map.get("timeStamp"), - TypeMapper.Criteria.GreaterEqual)); - criteria.add(new WhereCriterion(CriteriaId.timeStampLEQ, map.get("timeStamp"), - TypeMapper.Criteria.LessEqual)); - criteria.add(new WhereCriterion(CriteriaId.sessionID, map.get("session"), - TypeMapper.Criteria.Equal)); - criteria.add(new SortCriterion(map.get("timeStamp"), TypeMapper.Sort.Descending)); - criteria.add(new LimitCriterion(CriteriaId.limit)); - } - - @Override - public Id getId() { - return getDescending; - } - } - - private static class GetAscending extends Query<ThreadState> { - @Override - protected void describe(Criteria criteria) { - List<FieldDescriptor> descriptors = StatementUtils.createDescriptors(ThreadState.class); - final Map<String, FieldDescriptor> map = StatementUtils.createDescriptorMap(descriptors); - - criteria.add(new WhereCriterion(CriteriaId.vmId, map.get("vmId"), - TypeMapper.Criteria.Equal)); - criteria.add(new WhereCriterion(CriteriaId.agentId, map.get("agentId"), - TypeMapper.Criteria.Equal)); - criteria.add(new WhereCriterion(CriteriaId.timeStampGEQ, map.get("timeStamp"), - TypeMapper.Criteria.GreaterEqual)); - criteria.add(new WhereCriterion(CriteriaId.timeStampLEQ, map.get("timeStamp"), - TypeMapper.Criteria.LessEqual)); - criteria.add(new WhereCriterion(CriteriaId.sessionID, map.get("session"), - TypeMapper.Criteria.Equal)); - criteria.add(new SortCriterion(map.get("timeStamp"), TypeMapper.Sort.Ascending)); - criteria.add(new LimitCriterion(CriteriaId.limit)); - } - - @Override - public Id getId() { - return getAscending; - } - } - - private static final List<Query<ThreadState>> queries = new ArrayList<>(); - static { - queries.add(new GetDescending()); - queries.add(new GetAscending()); - } - - public static List<Query<ThreadState>> asList() { - return Collections.unmodifiableList(queries); - } -}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/statement/SummaryQuery.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl.statement; - -import com.redhat.thermostat.storage.core.experimental.statement.FieldDescriptor; -import com.redhat.thermostat.storage.core.Id; -import com.redhat.thermostat.storage.core.experimental.statement.LimitCriterion; -import com.redhat.thermostat.storage.core.experimental.statement.Query; -import com.redhat.thermostat.storage.core.experimental.statement.SortCriterion; -import com.redhat.thermostat.storage.core.experimental.statement.StatementUtils; -import com.redhat.thermostat.storage.core.experimental.statement.TypeMapper; -import com.redhat.thermostat.storage.core.experimental.statement.WhereCriterion; -import com.redhat.thermostat.thread.model.ThreadSession; -import com.redhat.thermostat.thread.model.ThreadSummary; -import java.util.List; -import java.util.Map; - -/** - * - */ -public class SummaryQuery extends Query<ThreadSummary> { - - public static final Id id = new Id(SummaryQuery.class.getSimpleName()); - - public static class CriteriaId { - public static final Id vmId = new Id("vmId"); - public static final Id agentId = new Id("agentId"); - public static final Id timeStampGEQ = new Id("timeStampGEQ"); - public static final Id timeStampLEQ = new Id("timeStampLEQ"); - public static final Id limit = new Id("limit"); - } - - @Override - public Id getId() { - return id; - } - - @Override - protected void describe(Criteria criteria) { - List<FieldDescriptor> descriptors = StatementUtils.createDescriptors - (ThreadSession.class); - final Map<String, FieldDescriptor> map = StatementUtils.createDescriptorMap(descriptors); - - criteria.add(new WhereCriterion(CriteriaId.vmId, map.get("vmId"), - TypeMapper.Criteria.Equal)); - criteria.add(new WhereCriterion(CriteriaId.agentId, map.get("agentId"), - TypeMapper.Criteria.Equal)); - criteria.add(new WhereCriterion(CriteriaId.timeStampGEQ, map.get("timeStamp"), - TypeMapper.Criteria.GreaterEqual)); - criteria.add(new WhereCriterion(CriteriaId.timeStampLEQ, map.get("timeStamp"), - TypeMapper.Criteria.LessEqual)); - - criteria.add(new SortCriterion(map.get("timeStamp"), TypeMapper.Sort.Descending)); - - criteria.add(new LimitCriterion(CriteriaId.limit)); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/internal/LockInfoDaoCategoryRegistration.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal; + +import java.util.HashSet; +import java.util.Set; + +import com.redhat.thermostat.storage.core.auth.CategoryRegistration; +import com.redhat.thermostat.thread.dao.LockInfoDao; + +public class LockInfoDaoCategoryRegistration implements CategoryRegistration { + + @Override + public Set<String> getCategoryNames() { + Set<String> set = new HashSet<>(); + set.add(LockInfoDao.LOCK_INFO_CATEGORY.getName()); + return set; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/internal/LockInfoDaoImpl.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,143 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal; + +import java.util.List; +import java.util.logging.Logger; + +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.PreparedStatement; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.core.VmBoundaryPojoGetter; +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.core.VmTimeIntervalPojoListGetter; +import com.redhat.thermostat.storage.dao.AbstractDao; +import com.redhat.thermostat.storage.dao.AbstractDaoStatement; +import com.redhat.thermostat.thread.dao.LockInfoDao; +import com.redhat.thermostat.thread.model.LockInfo; + +public class LockInfoDaoImpl extends AbstractDao implements LockInfoDao { + + private static final Logger logger = LoggingUtils.getLogger(LockInfoDaoImpl.class); + + static final String ADD_LOCK_INFO = "ADD " + LOCK_INFO_CATEGORY.getName() + + " SET '" + Key.AGENT_ID.getName() + "' = ?s , " + + "'" + Key.VM_ID.getName() + "' = ?s , " + + "'" + Key.TIMESTAMP.getName() + "' = ?l , " + + "'" + CONTENDED_LOCK_ATTEMPTS_KEY.getName() + "' = ?l , " + + "'" + DEFLATIONS_KEY.getName() + "' = ?l , " + + "'" + EMPTY_NOTIFICATIONS_KEY.getName() + "' = ?l , " + + "'" + FAILED_SPINS_KEY.getName() + "' = ?l , " + + "'" + FUTILE_WAKEUPS_KEY.getName() + "' = ?l , " + + "'" + INFLATIONS_KEY.getName() + "' = ?l , " + + "'" + MONITORS_EXTANT_KEY.getName() + "' = ?l , " + + "'" + MONITORS_IN_CIRCULATION_KEY.getName() + "' = ?l , " + + "'" + MONITORS_SCAVENGED_KEY.getName() + "' = ?l , " + + "'" + NOTIFICATIONS_KEY.getName() + "' = ?l , " + + "'" + PARKS_KEY.getName() + "' = ?l , " + + "'" + PRIVATE_A_KEY.getName() + "' = ?l , " + + "'" + PRIVATE_B_KEY.getName() + "' = ?l , " + + "'" + SLOW_ENTER_KEY.getName() + "' = ?l , " + + "'" + SLOW_EXIT_KEY.getName() + "' = ?l , " + + "'" + SLOW_NOTIFY_KEY.getName() + "' = ?l , " + + "'" + SLOW_NOTIFY_ALL_KEY.getName() + "' = ?l , " + + "'" + SUCCESSFUL_SPINS_KEY.getName() + "' = ?l"; + + private final Storage storage; + + private final VmBoundaryPojoGetter<LockInfo> boundaryGetter; + + private VmTimeIntervalPojoListGetter<LockInfo> intervalGetter; + + public LockInfoDaoImpl(Storage storage) { + this.storage = storage; + storage.registerCategory(LOCK_INFO_CATEGORY); + + boundaryGetter = new VmBoundaryPojoGetter<>(storage, LOCK_INFO_CATEGORY); + intervalGetter = new VmTimeIntervalPojoListGetter<>(storage, LOCK_INFO_CATEGORY); + } + + @Override + public void saveLockInfo(final LockInfo info) { + executeStatement(new AbstractDaoStatement<LockInfo>(storage, LOCK_INFO_CATEGORY, ADD_LOCK_INFO) { + @Override + public PreparedStatement<LockInfo> customize(PreparedStatement<LockInfo> preparedStatement) { + preparedStatement.setString(0, info.getAgentId()); + preparedStatement.setString(1, info.getVmId()); + preparedStatement.setLong(2, info.getTimeStamp()); + preparedStatement.setLong(3, info.getContendedLockAttempts()); + preparedStatement.setLong(4, info.getDeflations()); + preparedStatement.setLong(5, info.getEmptyNotifications()); + preparedStatement.setLong(6, info.getFailedSpins()); + preparedStatement.setLong(7, info.getFutileWakeups()); + preparedStatement.setLong(8, info.getInflations()); + preparedStatement.setLong(9, info.getMonExtant()); + preparedStatement.setLong(10, info.getMonInCirculation()); + preparedStatement.setLong(11, info.getMonScavenged()); + preparedStatement.setLong(12, info.getNotifications()); + preparedStatement.setLong(13, info.getParks()); + preparedStatement.setLong(14, info.getPrivateA()); + preparedStatement.setLong(15, info.getPrivateB()); + preparedStatement.setLong(16, info.getSlowEnter()); + preparedStatement.setLong(17, info.getSlowExit()); + preparedStatement.setLong(18, info.getSlowNotify()); + preparedStatement.setLong(19, info.getSlowNotifyAll()); + preparedStatement.setLong(20, info.getSuccessfulSpins()); + + return preparedStatement; + } + }); + } + + @Override + public List<LockInfo> getLockInfo(VmRef ref, Range<Long> range) { + return intervalGetter.getLatest(ref, range.getMin(), range.getMax()); + } + + @Override + public LockInfo getLatestLockInfo(VmRef ref) { + return boundaryGetter.getNewestStat(ref); + } + + @Override + protected Logger getLogger() { + return logger; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/internal/LockInfoDaoImplStatementDescriptorRegistration.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal; + +import java.util.HashSet; +import java.util.Set; + +import com.redhat.thermostat.storage.core.VmBoundaryPojoGetter; +import com.redhat.thermostat.storage.core.VmTimeIntervalPojoListGetter; +import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; +import com.redhat.thermostat.thread.dao.LockInfoDao; + +public class LockInfoDaoImplStatementDescriptorRegistration + implements StatementDescriptorRegistration { + + @Override + public Set<String> getStatementDescriptors() { + Set<String> set = new HashSet<>(); + + set.add(LockInfoDaoImpl.ADD_LOCK_INFO); + + String latestStatDescriptor = String.format( + VmBoundaryPojoGetter.DESC_NEWEST_VM_STAT, + LockInfoDao.LOCK_INFO_CATEGORY.getName()); + + set.add(latestStatDescriptor); + + String rangeStatDescriptor = String.format( + VmTimeIntervalPojoListGetter.VM_INTERVAL_QUERY_FORMAT, + LockInfoDao.LOCK_INFO_CATEGORY.getName()); + set.add(rangeStatDescriptor); + + return set; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/internal/ThreadDAOCategoryRegistration.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,66 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal; + +import java.util.HashSet; +import java.util.Set; + +import com.redhat.thermostat.storage.core.auth.CategoryRegistration; +import com.redhat.thermostat.thread.dao.ThreadDao; + +/** + * Registers the category used by this maven module. The web storage + * endpoint only allows categories to be registered which it knows of + * ahead of time. + * + */ +public class ThreadDAOCategoryRegistration implements CategoryRegistration { + + @Override + public Set<String> getCategoryNames() { + Set<String> categories = new HashSet<>(); + + categories.add(ThreadDao.DEADLOCK_INFO.getName()); + categories.add(ThreadDao.THREAD_HARVESTING_STATUS.getName()); + categories.add(ThreadDao.THREAD_CONTENTION_SAMPLE.getName()); + + ThreadDaoCategories.register(categories); + + return categories; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoCategories.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,86 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal; + +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.storage.core.Category; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.core.experimental.statement.CategoryBuilder; +import com.redhat.thermostat.storage.model.Pojo; +import com.redhat.thermostat.thread.model.ThreadSession; +import com.redhat.thermostat.thread.model.ThreadState; +import com.redhat.thermostat.thread.model.ThreadSummary; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.logging.Logger; + +/** + * + */ +public class ThreadDaoCategories { + + private static final Logger logger = LoggingUtils.getLogger(ThreadDaoCategories.class); + + public static class Categories { + public static final String SUMMARY = "vm-thread-summary"; + public static final String SESSION = "vm-thread-session"; + public static final String STATE = "vm-thread-state"; + + } + + static final List<Class<? extends Pojo>> BEANS = new ArrayList<>(); + static { + BEANS.add(ThreadSummary.class); + BEANS.add(ThreadSession.class); + BEANS.add(ThreadState.class); + } + + public static void register(Collection<String> collection) { + for (Class<? extends Pojo> beanClass: BEANS) { + Category<? extends Pojo> category = new CategoryBuilder(beanClass).build(); + collection.add(category.getName()); + } + } + + public static void register(Storage storage) { + for (Class<? extends Pojo> beanClass: BEANS) { + Category<? extends Pojo> category = new CategoryBuilder(beanClass).build(); + storage.registerCategory(category); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoImpl.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,355 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal; + +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.storage.core.Category; +import com.redhat.thermostat.storage.core.Cursor; +import com.redhat.thermostat.storage.core.DescriptorParsingException; +import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.PreparedStatement; +import com.redhat.thermostat.storage.core.StatementDescriptor; +import com.redhat.thermostat.storage.core.StatementExecutionException; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.core.experimental.statement.BeanAdapter; +import com.redhat.thermostat.storage.core.experimental.statement.BeanAdapterBuilder; +import com.redhat.thermostat.storage.core.Id; +import com.redhat.thermostat.storage.core.experimental.statement.Query; +import com.redhat.thermostat.storage.core.experimental.statement.QueryValues; +import com.redhat.thermostat.storage.core.experimental.statement.ResultHandler; +import com.redhat.thermostat.storage.model.Pojo; +import com.redhat.thermostat.thread.dao.ThreadDao; +import com.redhat.thermostat.thread.dao.internal.statement.SessionQueries; +import com.redhat.thermostat.thread.dao.internal.statement.StateQueries; +import com.redhat.thermostat.thread.dao.internal.statement.SummaryQuery; +import com.redhat.thermostat.thread.model.SessionID; +import com.redhat.thermostat.thread.model.ThreadHarvestingStatus; +import com.redhat.thermostat.thread.model.ThreadSession; +import com.redhat.thermostat.thread.model.ThreadState; +import com.redhat.thermostat.thread.model.ThreadSummary; +import com.redhat.thermostat.thread.model.VmDeadLockData; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static com.redhat.thermostat.common.utils.IteratorUtils.head; + +public class ThreadDaoImpl implements ThreadDao { + + private static final Logger logger = LoggingUtils.getLogger(ThreadDaoImpl.class); + + static final BeanAdapter<ThreadSummary> ThreadSummaryAdapter = new BeanAdapterBuilder<>(ThreadSummary.class, new SummaryQuery()).build(); + static final BeanAdapter<ThreadSession> ThreadSessionAdapter = new BeanAdapterBuilder<>(ThreadSession.class, SessionQueries.asList()).build(); + static final BeanAdapter<ThreadState> ThreadStateAdapter = new BeanAdapterBuilder<>(ThreadState.class, StateQueries.asList()).build(); + + static final String QUERY_LATEST_HARVESTING_STATUS = "QUERY " + + THREAD_HARVESTING_STATUS.getName() + " WHERE '" + + Key.AGENT_ID.getName() + "' = ?s AND '" + + Key.VM_ID.getName() + "' = ?s SORT '" + + Key.TIMESTAMP.getName() + "' DSC LIMIT 1"; + + static final String QUERY_LATEST_DEADLOCK_INFO = "QUERY " + + DEADLOCK_INFO.getName() + " WHERE '" + + Key.AGENT_ID.getName() + "' = ?s AND '" + + Key.VM_ID.getName() + "' = ?s SORT '" + + Key.TIMESTAMP.getName() + "' DSC LIMIT 1"; + + static final String DESC_ADD_THREAD_HARVESTING_STATUS = "ADD " + THREAD_HARVESTING_STATUS.getName() + + " SET '" + Key.AGENT_ID.getName() + "' = ?s , " + + "'" + Key.VM_ID.getName() + "' = ?s , " + + "'" + Key.TIMESTAMP.getName() + "' = ?l , " + + "'" + HARVESTING_STATUS_KEY.getName() + "' = ?b"; + + static final String DESC_ADD_THREAD_DEADLOCK_DATA = "ADD " + DEADLOCK_INFO.getName() + + " SET '" + Key.AGENT_ID.getName() + "' = ?s , " + + "'" + Key.VM_ID.getName() + "' = ?s , " + + "'" + Key.TIMESTAMP.getName() + "' = ?l , " + + "'" + DEADLOCK_DESCRIPTION_KEY.getName() + "' = ?s"; + + + static final String ADD_CONTENTION_SAMPLE = + "ADD " + THREAD_CONTENTION_SAMPLE.getName() + " " + + "SET '" + Key.AGENT_ID.getName() + "' = ?s , " + + "'" + Key.VM_ID.getName() + "' = ?s , " + + "'" + THREAD_CONTENTION_BLOCKED_COUNT_KEY.getName() + "' = ?l , " + + "'" + THREAD_CONTENTION_BLOCKED_TIME_KEY.getName() + "' = ?l , " + + "'" + THREAD_CONTENTION_WAITED_COUNT_KEY.getName() + "' = ?l , " + + "'" + THREAD_CONTENTION_WAITED_TIME_KEY.getName() + "' = ?l , " + + "'" + ThreadDaoKeys.THREAD_HEADER_UUID.getName() + "' = ?s , " + + "'" + Key.TIMESTAMP.getName() + "' = ?l"; + + static final String GET_LATEST_CONTENTION_SAMPLE= "QUERY " + + THREAD_CONTENTION_SAMPLE.getName() + " WHERE '" + + ThreadDaoKeys.THREAD_HEADER_UUID.getName() + "' = ?s SORT '" + + Key.TIMESTAMP.getName() + "' DSC LIMIT 1"; + + private Storage storage; + + public ThreadDaoImpl(Storage storage) { + this.storage = storage; + + ThreadDaoCategories.register(storage); + + storage.registerCategory(THREAD_HARVESTING_STATUS); + storage.registerCategory(THREAD_CONTENTION_SAMPLE); + + storage.registerCategory(DEADLOCK_INFO); + } + + @Override + public void saveSummary(ThreadSummary summary) { + try { + ThreadSummaryAdapter.insert(summary, storage); + + } catch (StatementExecutionException e) { + logger.log(Level.SEVERE, "Exception saving summary: " + summary, e); + } + } + + @Override + public void addThreadState(ThreadState thread) { + try { + ThreadStateAdapter.insert(thread, storage); + + } catch (StatementExecutionException e) { + logger.log(Level.SEVERE, "Exception saving thread state: " + thread, e); + } + } + + @Override + public void getThreadStates(VmRef ref, SessionID session, + final ResultHandler<ThreadState> handler, + Range<Long> range, int limit, Sort order) + { + Id id = order.equals(Sort.ASCENDING) ? StateQueries.getAscending : + StateQueries.getDescending; + + Query<ThreadState> query = ThreadStateAdapter.getQuery(id); + + QueryValues values = query.createValues(); + values.set(StateQueries.CriteriaId.vmId, ref.getVmId()); + values.set(StateQueries.CriteriaId.agentId, ref.getHostRef().getAgentId()); + values.set(StateQueries.CriteriaId.sessionID, session.get()); + + values.set(StateQueries.CriteriaId.timeStampGEQ, range.getMin()); + values.set(StateQueries.CriteriaId.timeStampLEQ, range.getMax()); + values.set(StateQueries.CriteriaId.limit, limit); + + try { + ThreadStateAdapter.query(values, handler, storage); + + } catch (StatementExecutionException e) { + logger.log(Level.SEVERE, "Exception retrieving thread summary", e); + } + } + + @Override + public List<ThreadSummary> getSummary(VmRef ref, Range<Long> range, int limit) { + final List<ThreadSummary> results = new ArrayList<>(); + + Query<ThreadSummary> query = ThreadSummaryAdapter.getQuery(SummaryQuery.id); + + QueryValues values = query.createValues(); + values.set(SummaryQuery.CriteriaId.vmId, ref.getVmId()); + values.set(SummaryQuery.CriteriaId.agentId, ref.getHostRef().getAgentId()); + + values.set(SummaryQuery.CriteriaId.timeStampGEQ, range.getMin()); + values.set(SummaryQuery.CriteriaId.timeStampLEQ, range.getMax()); + values.set(SummaryQuery.CriteriaId.limit, limit); + + try { + ThreadSummaryAdapter.query(values, new ResultHandler<ThreadSummary>() { + @Override + public boolean onResult(ThreadSummary result) { + results.add(result); + return true; + } + }, storage); + + } catch (StatementExecutionException e) { + logger.log(Level.SEVERE, "Exception retrieving thread summary", e); + } + + return results; + } + + @Override + public List<ThreadSession> getSessions(VmRef ref, Range<Long> range, + int limit, Sort order) + { + final List<ThreadSession> results = new ArrayList<>(); + + Id id = order.equals(Sort.ASCENDING) ? SessionQueries.getRangeAscending : + SessionQueries.getRangeDescending; + + Query<ThreadSession> query = ThreadSessionAdapter.getQuery(id); + + QueryValues values = query.createValues(); + values.set(SessionQueries.CriteriaId.vmId, ref.getVmId()); + values.set(SessionQueries.CriteriaId.agentId, ref.getHostRef().getAgentId()); + + values.set(SessionQueries.CriteriaId.timeStampGEQ, range.getMin()); + values.set(SessionQueries.CriteriaId.timeStampLEQ, range.getMax()); + values.set(SessionQueries.CriteriaId.limit, limit); + + try { + ThreadSessionAdapter.query(values, new ResultHandler<ThreadSession>() { + @Override + public boolean onResult(ThreadSession result) { + results.add(result); + return true; + } + }, storage); + + } catch (StatementExecutionException e) { + logger.log(Level.SEVERE, "Exception retrieving thread session", e); + } + + return results; + } + + public void saveSession(ThreadSession session) { + try { + ThreadSessionAdapter.insert(session, storage); + + } catch (StatementExecutionException e) { + logger.log(Level.SEVERE, "Exception saving session: " + session, e); + } + } + + @Override + public void saveHarvestingStatus(ThreadHarvestingStatus status) { + StatementDescriptor<ThreadHarvestingStatus> desc = new StatementDescriptor<>(THREAD_HARVESTING_STATUS, DESC_ADD_THREAD_HARVESTING_STATUS); + PreparedStatement<ThreadHarvestingStatus> prepared; + try { + prepared = storage.prepareStatement(desc); + prepared.setString(0, status.getAgentId()); + prepared.setString(1, status.getVmId()); + prepared.setLong(2, status.getTimeStamp()); + prepared.setBoolean(3, status.isHarvesting()); + prepared.execute(); + } catch (DescriptorParsingException e) { + logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e); + } catch (StatementExecutionException e) { + logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e); + } + } + + @Override + public ThreadHarvestingStatus getLatestHarvestingStatus(VmRef vm) { + PreparedStatement<ThreadHarvestingStatus> stmt = prepareQuery(THREAD_HARVESTING_STATUS, + QUERY_LATEST_HARVESTING_STATUS, vm); + if (stmt == null) { + return null; + } + + return getFirstResult(stmt); + } + + @Override + public VmDeadLockData loadLatestDeadLockStatus(VmRef ref) { + PreparedStatement<VmDeadLockData> stmt = prepareQuery(DEADLOCK_INFO, QUERY_LATEST_DEADLOCK_INFO, ref); + if (stmt == null) { + return null; + } + + return getFirstResult(stmt); + } + + @Override + public void saveDeadLockStatus(VmDeadLockData deadLockInfo) { + StatementDescriptor<VmDeadLockData> desc = new StatementDescriptor<>(DEADLOCK_INFO, DESC_ADD_THREAD_DEADLOCK_DATA); + PreparedStatement<VmDeadLockData> prepared; + try { + prepared = storage.prepareStatement(desc); + prepared.setString(0, deadLockInfo.getAgentId()); + prepared.setString(1, deadLockInfo.getVmId()); + prepared.setLong(2, deadLockInfo.getTimeStamp()); + prepared.setString(3, deadLockInfo.getDeadLockDescription()); + prepared.execute(); + } catch (DescriptorParsingException e) { + logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e); + } catch (StatementExecutionException e) { + logger.log(Level.SEVERE, "Executing stmt '" + desc + "' failed!", e); + } + } + + + /**************************************************************************/ + + private <T extends Pojo> PreparedStatement<T> prepareQuery(Category<T> category, String query, VmRef ref) { + return prepareQuery(category, query, ref, null, null); + } + + private <T extends Pojo> PreparedStatement<T> prepareQuery(Category<T> category, String query, VmRef ref, Long since, Long to) { + StatementDescriptor<T> desc = new StatementDescriptor<>(category, query); + PreparedStatement<T> stmt = null; + try { + stmt = storage.prepareStatement(desc); + stmt.setString(0, ref.getHostRef().getAgentId()); + stmt.setString(1, ref.getVmId()); + // assume: the format of the query is such that 2nd and 3rd arguments (if any) are longs + if (since != null) { + stmt.setLong(2, since); + } + if (to != null) { + stmt.setLong(3, to); + } + } catch (DescriptorParsingException e) { + // should not happen, but if it *does* happen, at least log it + logger.log(Level.SEVERE, "Preparing query '" + desc + "' failed!", e); + } + return stmt; + } + + private <T extends Pojo> T getFirstResult(PreparedStatement<T> stmt) { + Cursor<T> cursor; + try { + cursor = stmt.executeQuery(); + } catch (StatementExecutionException e) { + // should not happen, but if it *does* happen, at least log it + logger.log(Level.SEVERE, "Executing query '" + stmt + "' failed!", e); + return null; + } + + return head(cursor); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoImplStatementDescriptorRegistration.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal; + +import java.util.HashSet; +import java.util.Set; + +import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; + +/** + * Registers prepared queries issued by this maven module via + * via {@link ThreadDaoImpl}. + * + */ +public class ThreadDaoImplStatementDescriptorRegistration implements + StatementDescriptorRegistration { + + private final Set<String> descs; + + public ThreadDaoImplStatementDescriptorRegistration() { + descs = new HashSet<>(); + descs.add(ThreadDaoImpl.QUERY_LATEST_DEADLOCK_INFO); + descs.add(ThreadDaoImpl.QUERY_LATEST_HARVESTING_STATUS); + + // TODO: this needs to go in an helper class + descs.addAll(ThreadDaoImpl.ThreadSummaryAdapter.describeStatements()); + descs.addAll(ThreadDaoImpl.ThreadSessionAdapter.describeStatements()); + descs.addAll(ThreadDaoImpl.ThreadStateAdapter.describeStatements()); + + descs.add(ThreadDaoImpl.DESC_ADD_THREAD_DEADLOCK_DATA); + descs.add(ThreadDaoImpl.DESC_ADD_THREAD_HARVESTING_STATUS); + descs.add(ThreadDaoImpl.ADD_CONTENTION_SAMPLE); + descs.add(ThreadDaoImpl.GET_LATEST_CONTENTION_SAMPLE); + } + + @Override + public Set<String> getStatementDescriptors() { + return descs; + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoKeys.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal; + +import com.redhat.thermostat.storage.core.Key; + +/** + * + */ +public class ThreadDaoKeys { + + public static final Key<String> THREAD_HEADER_UUID = new Key<String>("referenceID"); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/internal/statement/SessionQueries.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,131 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal.statement; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import com.redhat.thermostat.storage.core.Id; +import com.redhat.thermostat.storage.core.experimental.statement.FieldDescriptor; +import com.redhat.thermostat.storage.core.experimental.statement.LimitCriterion; +import com.redhat.thermostat.storage.core.experimental.statement.Query; +import com.redhat.thermostat.storage.core.experimental.statement.SortCriterion; +import com.redhat.thermostat.storage.core.experimental.statement.StatementUtils; +import com.redhat.thermostat.storage.core.experimental.statement.TypeMapper; +import com.redhat.thermostat.storage.core.experimental.statement.WhereCriterion; +import com.redhat.thermostat.thread.model.ThreadSession; + +/** + * + */ +public class SessionQueries { + + public static final Id getRangeAscending = new Id("SessionQueries::getRangeAscending"); + public static final Id getRangeDescending = new Id("SessionQueries::getRangeDescending"); + + public static class CriteriaId { + public static final Id vmId = new Id("vmId"); + public static final Id agentId = new Id("agentId"); + public static final Id timeStampGEQ = new Id("timeStampGEQ"); + public static final Id timeStampLEQ = new Id("timeStampLEQ"); + public static final Id limit = new Id("limit"); + } + + private static class GetDescending extends Query<ThreadSession> { + @Override + protected void describe(Criteria criteria) { + List<FieldDescriptor> descriptors = StatementUtils.createDescriptors(ThreadSession.class); + final Map<String, FieldDescriptor> map = StatementUtils.createDescriptorMap(descriptors); + + criteria.add(new WhereCriterion(CriteriaId.vmId, map.get("vmId"), + TypeMapper.Criteria.Equal)); + criteria.add(new WhereCriterion(CriteriaId.agentId, map.get("agentId"), + TypeMapper.Criteria.Equal)); + + criteria.add(new WhereCriterion(CriteriaId.timeStampGEQ, map.get("timeStamp"), + TypeMapper.Criteria.GreaterEqual)); + criteria.add(new WhereCriterion(CriteriaId.timeStampLEQ, map.get("timeStamp"), + TypeMapper.Criteria.LessEqual)); + + criteria.add(new SortCriterion(map.get("timeStamp"), TypeMapper.Sort.Descending)); + criteria.add(new LimitCriterion(CriteriaId.limit)); + } + + @Override + public Id getId() { + return getRangeDescending; + } + } + + private static class GetAscending extends Query<ThreadSession> { + @Override + protected void describe(Criteria criteria) { + List<FieldDescriptor> descriptors = StatementUtils.createDescriptors(ThreadSession.class); + final Map<String, FieldDescriptor> map = StatementUtils.createDescriptorMap(descriptors); + + criteria.add(new WhereCriterion(CriteriaId.vmId, map.get("vmId"), + TypeMapper.Criteria.Equal)); + criteria.add(new WhereCriterion(CriteriaId.agentId, map.get("agentId"), + TypeMapper.Criteria.Equal)); + + criteria.add(new WhereCriterion(CriteriaId.timeStampGEQ, map.get("timeStamp"), + TypeMapper.Criteria.GreaterEqual)); + criteria.add(new WhereCriterion(CriteriaId.timeStampLEQ, map.get("timeStamp"), + TypeMapper.Criteria.LessEqual)); + + criteria.add(new SortCriterion(map.get("timeStamp"), TypeMapper.Sort.Ascending)); + criteria.add(new LimitCriterion(CriteriaId.limit)); + } + + @Override + public Id getId() { + return getRangeAscending; + } + } + + private static final List<Query<ThreadSession>> queries = new ArrayList<>(); + static { + queries.add(new GetDescending()); + queries.add(new GetAscending()); + } + + public static List<Query<ThreadSession>> asList() { + return Collections.unmodifiableList(queries); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/internal/statement/StateQueries.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,131 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal.statement; + +import com.redhat.thermostat.storage.core.experimental.statement.FieldDescriptor; +import com.redhat.thermostat.storage.core.Id; +import com.redhat.thermostat.storage.core.experimental.statement.LimitCriterion; +import com.redhat.thermostat.storage.core.experimental.statement.Query; +import com.redhat.thermostat.storage.core.experimental.statement.SortCriterion; +import com.redhat.thermostat.storage.core.experimental.statement.StatementUtils; +import com.redhat.thermostat.storage.core.experimental.statement.TypeMapper; +import com.redhat.thermostat.storage.core.experimental.statement.WhereCriterion; +import com.redhat.thermostat.thread.model.ThreadState; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * + */ +public class StateQueries { + + public static final Id getAscending = new Id("StateQueries::getRangeAscending"); + public static final Id getDescending = new Id("StateQueries::getRangeDescending"); + + public static class CriteriaId { + public static final Id vmId = new Id("vmId"); + public static final Id agentId = new Id("agentId"); + public static final Id timeStampGEQ = new Id("timeStampGEQ"); + public static final Id timeStampLEQ = new Id("timeStampLEQ"); + public static final Id sessionID = new Id("sessionID"); + public static final Id limit = new Id("limit"); + } + + private static class GetDescending extends Query<ThreadState> { + @Override + protected void describe(Criteria criteria) { + List<FieldDescriptor> descriptors = StatementUtils.createDescriptors(ThreadState.class); + final Map<String, FieldDescriptor> map = StatementUtils.createDescriptorMap(descriptors); + + criteria.add(new WhereCriterion(CriteriaId.vmId, map.get("vmId"), + TypeMapper.Criteria.Equal)); + criteria.add(new WhereCriterion(CriteriaId.agentId, map.get("agentId"), + TypeMapper.Criteria.Equal)); + criteria.add(new WhereCriterion(CriteriaId.timeStampGEQ, map.get("timeStamp"), + TypeMapper.Criteria.GreaterEqual)); + criteria.add(new WhereCriterion(CriteriaId.timeStampLEQ, map.get("timeStamp"), + TypeMapper.Criteria.LessEqual)); + criteria.add(new WhereCriterion(CriteriaId.sessionID, map.get("session"), + TypeMapper.Criteria.Equal)); + criteria.add(new SortCriterion(map.get("timeStamp"), TypeMapper.Sort.Descending)); + criteria.add(new LimitCriterion(CriteriaId.limit)); + } + + @Override + public Id getId() { + return getDescending; + } + } + + private static class GetAscending extends Query<ThreadState> { + @Override + protected void describe(Criteria criteria) { + List<FieldDescriptor> descriptors = StatementUtils.createDescriptors(ThreadState.class); + final Map<String, FieldDescriptor> map = StatementUtils.createDescriptorMap(descriptors); + + criteria.add(new WhereCriterion(CriteriaId.vmId, map.get("vmId"), + TypeMapper.Criteria.Equal)); + criteria.add(new WhereCriterion(CriteriaId.agentId, map.get("agentId"), + TypeMapper.Criteria.Equal)); + criteria.add(new WhereCriterion(CriteriaId.timeStampGEQ, map.get("timeStamp"), + TypeMapper.Criteria.GreaterEqual)); + criteria.add(new WhereCriterion(CriteriaId.timeStampLEQ, map.get("timeStamp"), + TypeMapper.Criteria.LessEqual)); + criteria.add(new WhereCriterion(CriteriaId.sessionID, map.get("session"), + TypeMapper.Criteria.Equal)); + criteria.add(new SortCriterion(map.get("timeStamp"), TypeMapper.Sort.Ascending)); + criteria.add(new LimitCriterion(CriteriaId.limit)); + } + + @Override + public Id getId() { + return getAscending; + } + } + + private static final List<Query<ThreadState>> queries = new ArrayList<>(); + static { + queries.add(new GetDescending()); + queries.add(new GetAscending()); + } + + public static List<Query<ThreadState>> asList() { + return Collections.unmodifiableList(queries); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/internal/statement/SummaryQuery.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,91 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal.statement; + +import com.redhat.thermostat.storage.core.experimental.statement.FieldDescriptor; +import com.redhat.thermostat.storage.core.Id; +import com.redhat.thermostat.storage.core.experimental.statement.LimitCriterion; +import com.redhat.thermostat.storage.core.experimental.statement.Query; +import com.redhat.thermostat.storage.core.experimental.statement.SortCriterion; +import com.redhat.thermostat.storage.core.experimental.statement.StatementUtils; +import com.redhat.thermostat.storage.core.experimental.statement.TypeMapper; +import com.redhat.thermostat.storage.core.experimental.statement.WhereCriterion; +import com.redhat.thermostat.thread.model.ThreadSession; +import com.redhat.thermostat.thread.model.ThreadSummary; +import java.util.List; +import java.util.Map; + +/** + * + */ +public class SummaryQuery extends Query<ThreadSummary> { + + public static final Id id = new Id(SummaryQuery.class.getSimpleName()); + + public static class CriteriaId { + public static final Id vmId = new Id("vmId"); + public static final Id agentId = new Id("agentId"); + public static final Id timeStampGEQ = new Id("timeStampGEQ"); + public static final Id timeStampLEQ = new Id("timeStampLEQ"); + public static final Id limit = new Id("limit"); + } + + @Override + public Id getId() { + return id; + } + + @Override + protected void describe(Criteria criteria) { + List<FieldDescriptor> descriptors = StatementUtils.createDescriptors + (ThreadSession.class); + final Map<String, FieldDescriptor> map = StatementUtils.createDescriptorMap(descriptors); + + criteria.add(new WhereCriterion(CriteriaId.vmId, map.get("vmId"), + TypeMapper.Criteria.Equal)); + criteria.add(new WhereCriterion(CriteriaId.agentId, map.get("agentId"), + TypeMapper.Criteria.Equal)); + criteria.add(new WhereCriterion(CriteriaId.timeStampGEQ, map.get("timeStamp"), + TypeMapper.Criteria.GreaterEqual)); + criteria.add(new WhereCriterion(CriteriaId.timeStampLEQ, map.get("timeStamp"), + TypeMapper.Criteria.LessEqual)); + + criteria.add(new SortCriterion(map.get("timeStamp"), TypeMapper.Sort.Descending)); + + criteria.add(new LimitCriterion(CriteriaId.limit)); + } +}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSession.java Wed Apr 06 14:52:26 2016 +0200 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSession.java Fri Apr 08 13:18:48 2016 +0200 @@ -40,7 +40,7 @@ import com.redhat.thermostat.storage.core.Persist; import com.redhat.thermostat.storage.model.BasePojo; import com.redhat.thermostat.storage.model.TimeStampedPojo; -import com.redhat.thermostat.thread.dao.impl.ThreadDaoCategories; +import com.redhat.thermostat.thread.dao.internal.ThreadDaoCategories; import com.redhat.thermostat.storage.core.experimental.statement.Category; import com.redhat.thermostat.storage.core.experimental.statement.Indexed;
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadState.java Wed Apr 06 14:52:26 2016 +0200 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadState.java Fri Apr 08 13:18:48 2016 +0200 @@ -42,7 +42,7 @@ import com.redhat.thermostat.storage.core.experimental.statement.Indexed; import com.redhat.thermostat.storage.model.BasePojo; import com.redhat.thermostat.storage.model.TimeStampedPojo; -import com.redhat.thermostat.thread.dao.impl.ThreadDaoCategories; +import com.redhat.thermostat.thread.dao.internal.ThreadDaoCategories; /** * Represents a single delta variation of a Thread state.
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSummary.java Wed Apr 06 14:52:26 2016 +0200 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSummary.java Fri Apr 08 13:18:48 2016 +0200 @@ -40,7 +40,7 @@ import com.redhat.thermostat.storage.core.Persist; import com.redhat.thermostat.storage.model.BasePojo; import com.redhat.thermostat.storage.model.TimeStampedPojo; -import com.redhat.thermostat.thread.dao.impl.ThreadDaoCategories; +import com.redhat.thermostat.thread.dao.internal.ThreadDaoCategories; import com.redhat.thermostat.storage.core.experimental.statement.Category; import com.redhat.thermostat.storage.core.experimental.statement.Indexed;
--- a/thread/collector/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.CategoryRegistration Wed Apr 06 14:52:26 2016 +0200 +++ b/thread/collector/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.CategoryRegistration Fri Apr 08 13:18:48 2016 +0200 @@ -1,2 +1,2 @@ -com.redhat.thermostat.thread.dao.impl.ThreadDAOCategoryRegistration -com.redhat.thermostat.thread.dao.impl.LockInfoDaoCategoryRegistration +com.redhat.thermostat.thread.dao.internal.ThreadDAOCategoryRegistration +com.redhat.thermostat.thread.dao.internal.LockInfoDaoCategoryRegistration
--- a/thread/collector/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration Wed Apr 06 14:52:26 2016 +0200 +++ b/thread/collector/src/main/resources/META-INF/services/com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration Fri Apr 08 13:18:48 2016 +0200 @@ -1,2 +1,2 @@ -com.redhat.thermostat.thread.dao.impl.ThreadDaoImplStatementDescriptorRegistration -com.redhat.thermostat.thread.dao.impl.LockInfoDaoImplStatementDescriptorRegistration +com.redhat.thermostat.thread.dao.internal.ThreadDaoImplStatementDescriptorRegistration +com.redhat.thermostat.thread.dao.internal.LockInfoDaoImplStatementDescriptorRegistration
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/LockInfoDaoCategoryRegistrationTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.Set; - -import org.junit.Test; - -import com.redhat.thermostat.storage.core.auth.CategoryRegistration; -import com.redhat.thermostat.testutils.ServiceLoaderTest; - -public class LockInfoDaoCategoryRegistrationTest extends ServiceLoaderTest<CategoryRegistration> { - - public LockInfoDaoCategoryRegistrationTest() { - super(CategoryRegistration.class, STORAGE_SERVICES + 1, /* from TheadDao */ - LockInfoDaoCategoryRegistration.class); - } - - @Test - public void verifyKnownsCategory() { - Set<String> names = - new LockInfoDaoCategoryRegistration().getCategoryNames(); - assertEquals(1, names.size()); - assertTrue(names.contains("vm-thread-lock")); - } - -}
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/LockInfoDaoImplStatementDescriptorRegistrationTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl; - -import static org.junit.Assert.assertEquals; - -import java.util.Set; - -import org.junit.Test; - -import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; -import com.redhat.thermostat.testutils.ServiceLoaderTest; - -public class LockInfoDaoImplStatementDescriptorRegistrationTest extends ServiceLoaderTest<StatementDescriptorRegistration> { - - public LockInfoDaoImplStatementDescriptorRegistrationTest() { - super(StatementDescriptorRegistration.class, STORAGE_SERVICES + 1 /* from thread dao */, LockInfoDaoImplStatementDescriptorRegistration.class); - } - - @Test - public void verifyExportsStatements() { - Set<String> statements = - new LockInfoDaoImplStatementDescriptorRegistration().getStatementDescriptors(); - - assertEquals(3, statements.size()); - } - -}
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOCategoryRegistrationTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.HashSet; -import java.util.Set; - -import org.junit.Test; - -import com.redhat.thermostat.storage.core.auth.CategoryRegistration; -import com.redhat.thermostat.testutils.ServiceLoaderTest; -import com.redhat.thermostat.thread.dao.ThreadDao; - -public class ThreadDAOCategoryRegistrationTest extends ServiceLoaderTest<CategoryRegistration> { - - private static final int EXPECTED_CATEGORIES = 6; - - public ThreadDAOCategoryRegistrationTest() { - super(CategoryRegistration.class, STORAGE_SERVICES + 1 /* from lock dao */, - ThreadDAOCategoryRegistration.class); - } - - @Test - public void registersAllCategories() { - ThreadDAOCategoryRegistration reg = new ThreadDAOCategoryRegistration(); - Set<String> categories = reg.getCategoryNames(); - assertEquals(EXPECTED_CATEGORIES, categories.size()); - - assertFalse("null descriptor not allowed", categories.contains(null)); - - assertTrue(categories.contains(ThreadDao.DEADLOCK_INFO.getName())); - assertTrue(categories.contains(ThreadDao.THREAD_HARVESTING_STATUS.getName())); - assertTrue(categories.contains(ThreadDao.THREAD_CONTENTION_SAMPLE.getName())); - - Set<String> sourceCategories = new HashSet<>(); - ThreadDaoCategories.register(sourceCategories); - - for (String category : sourceCategories) { - assertTrue(categories.contains(category)); - } - } - -} -
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoCategoriesTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl; - -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.storage.core.experimental.statement.Category; -import com.redhat.thermostat.storage.core.experimental.statement.CategoryBuilder; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -public class ThreadDaoCategoriesTest { - - @Test - public void testRegister() throws Exception { - Set<String> set = new HashSet<>(); - ThreadDaoCategories.register(set); - - assertEquals(ThreadDaoCategories.BEANS.size(), set.size()); - for (Class<? extends Pojo> categoryClass : ThreadDaoCategories.BEANS) { - String name = categoryClass.getAnnotation(Category.class).value(); - assertTrue(set.contains(name)); - } - } - - @Test - public void testRegisterInStorage() throws Exception { - Storage storage = mock(Storage.class); - - List<com.redhat.thermostat.storage.core.Category<?>> categories = - new ArrayList<>(); - for (Class<? extends Pojo> categoryClass : ThreadDaoCategories.BEANS) { - categories.add(new CategoryBuilder(categoryClass).build()); - } - - ThreadDaoCategories.register(storage); - for (com.redhat.thermostat.storage.core.Category<?> category : categories) { - verify(storage).registerCategory(category); - } - } -}
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplStatementDescriptorRegistrationTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; - -import java.util.Set; - -import org.junit.Test; - -import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; -import com.redhat.thermostat.testutils.ServiceLoaderTest; - -public class ThreadDaoImplStatementDescriptorRegistrationTest extends ServiceLoaderTest<StatementDescriptorRegistration> { - - public ThreadDaoImplStatementDescriptorRegistrationTest() { - super(StatementDescriptorRegistration.class, STORAGE_SERVICES + 1 /* from lock dao */, ThreadDaoImplStatementDescriptorRegistration.class); - } - - @Test - public void registersAllDescriptors() { - ThreadDaoImplStatementDescriptorRegistration reg = new ThreadDaoImplStatementDescriptorRegistration(); - Set<String> descriptors = reg.getStatementDescriptors(); - assertEquals(14, descriptors.size()); - assertFalse("null statement not allowed", descriptors.contains(null)); - } - -} -
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,262 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl; - -import com.redhat.thermostat.storage.core.Cursor; -import com.redhat.thermostat.storage.core.DescriptorParsingException; -import com.redhat.thermostat.storage.core.HostRef; -import com.redhat.thermostat.storage.core.PreparedStatement; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.core.StatementExecutionException; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.VmRef; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.thread.dao.ThreadDao; -import com.redhat.thermostat.thread.model.ThreadHarvestingStatus; -import com.redhat.thermostat.thread.model.VmDeadLockData; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -public class ThreadDaoImplTest { - - private static final String AGENT_ID = "0xcafe"; - private static final String VM_ID = "VM42"; - - private VmRef vmRef; - private HostRef hostRef; - - @Before - public void setUp() { - hostRef = mock(HostRef.class); - when(hostRef.getAgentId()).thenReturn(AGENT_ID); - - vmRef = mock(VmRef.class); - when(vmRef.getHostRef()).thenReturn(hostRef); - when(vmRef.getVmId()).thenReturn(VM_ID); - } - - @Test - public void preparedQueryDescriptorsAreSane() { - - String expectedQueryLatestHarvestingStatus = "QUERY vm-thread-harvesting WHERE 'agentId' = ?s AND 'vmId' = ?s SORT 'timeStamp' DSC LIMIT 1"; - assertEquals(expectedQueryLatestHarvestingStatus, ThreadDaoImpl.QUERY_LATEST_HARVESTING_STATUS); - - String expectedQueryThreadLatestDeadlockInfo = "QUERY vm-deadlock-data WHERE 'agentId' = ?s AND 'vmId' = ?s SORT 'timeStamp' DSC LIMIT 1"; - assertEquals(expectedQueryThreadLatestDeadlockInfo, ThreadDaoImpl.QUERY_LATEST_DEADLOCK_INFO); - - String addThreadHarvesting = "ADD vm-thread-harvesting SET 'agentId' = ?s , " + - "'vmId' = ?s , " + - "'timeStamp' = ?l , " + - "'harvesting' = ?b"; - assertEquals(addThreadHarvesting, ThreadDaoImpl.DESC_ADD_THREAD_HARVESTING_STATUS); - - String addThreadInfo = "ADD vm-thread-header SET 'agentId' = ?s , " + - "'vmId' = ?s , " + - "'threadName' = ?s , " + - "'threadId' = ?l , " + - "'timeStamp' = ?l , " + - "'referenceID' = ?s"; - - String addContentionSample = "ADD thread-contention-sample SET " + - "'agentId' = ?s , 'vmId' = ?s , 'blockedCount' = ?l , " + - "'blockedTime' = ?l , 'waitedCount' = ?l , " + - "'waitedTime' = ?l , 'referenceID' = ?s , 'timeStamp' = ?l"; - assertEquals(addContentionSample, ThreadDaoImpl.ADD_CONTENTION_SAMPLE); - - String getLatestContentionSample = "QUERY thread-contention-sample " + - "WHERE 'referenceID' = ?s SORT 'timeStamp' DSC LIMIT 1"; - assertEquals(getLatestContentionSample, ThreadDaoImpl.GET_LATEST_CONTENTION_SAMPLE); - - String getFirstThreadState = "QUERY vm-thread-state WHERE " + - "'agentId' = ?s AND 'referenceID' = ?s SORT 'probeStartTime' " + - "ASC LIMIT 1"; - } - - @Test - public void testThreadDaoCategoryRegistration() { - Storage storage = mock(Storage.class); - - @SuppressWarnings("unused") - ThreadDaoImpl dao = new ThreadDaoImpl(storage); - - verify(storage).registerCategory(ThreadDao.THREAD_HARVESTING_STATUS); - } - - @SuppressWarnings("unchecked") - private <T extends Pojo> StatementDescriptor<T> anyDescriptor(Class<T> type) { - return (StatementDescriptor<T>) any(StatementDescriptor.class); - } - - @Test - public void testLoadLatestDeadLockStatusWithNoData() throws Exception { - Storage storage = mock(Storage.class); - @SuppressWarnings("unchecked") - PreparedStatement<VmDeadLockData> stmt = (PreparedStatement<VmDeadLockData>) mock(PreparedStatement.class); - when(storage.prepareStatement(anyDescriptor(VmDeadLockData.class))).thenReturn(stmt); - @SuppressWarnings("unchecked") - Cursor<VmDeadLockData> cursor = (Cursor<VmDeadLockData>) mock(Cursor.class); - - when(cursor.hasNext()).thenReturn(false); - when(cursor.next()).thenThrow(new IllegalStateException("must not do this")); - when(stmt.executeQuery()).thenReturn(cursor); - - ThreadDaoImpl dao = new ThreadDaoImpl(storage); - VmDeadLockData result = dao.loadLatestDeadLockStatus(vmRef); - - assertNull(result); - } - - @Test - public void testLoadLatestDeadLockStatus() throws DescriptorParsingException, StatementExecutionException { - Storage storage = mock(Storage.class); - @SuppressWarnings("unchecked") - PreparedStatement<VmDeadLockData> stmt = (PreparedStatement<VmDeadLockData>) mock(PreparedStatement.class); - when(storage.prepareStatement(anyDescriptor(VmDeadLockData.class))).thenReturn(stmt); - @SuppressWarnings("unchecked") - Cursor<VmDeadLockData> cursor = (Cursor<VmDeadLockData>) mock(Cursor.class); - VmDeadLockData data = mock(VmDeadLockData.class); - - when(cursor.hasNext()).thenReturn(true); - when(cursor.next()).thenReturn(data); - when(stmt.executeQuery()).thenReturn(cursor); - - ThreadDaoImpl dao = new ThreadDaoImpl(storage); - VmDeadLockData result = dao.loadLatestDeadLockStatus(vmRef); - - assertSame(data, result); - - verify(storage).prepareStatement(anyDescriptor(VmDeadLockData.class)); - verify(stmt).setString(0, AGENT_ID); - verify(stmt).setString(1, VM_ID); - verify(stmt).executeQuery(); - verifyNoMoreInteractions(stmt); - } - - @SuppressWarnings("unchecked") - @Test - public void testSaveDeadLockStatus() throws DescriptorParsingException, StatementExecutionException { - Storage storage = mock(Storage.class); - PreparedStatement<VmDeadLockData> add = mock(PreparedStatement.class); - when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add); - - VmDeadLockData status = mock(VmDeadLockData.class); - - ThreadDaoImpl dao = new ThreadDaoImpl(storage); - dao.saveDeadLockStatus(status); - - @SuppressWarnings("rawtypes") - ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class); - - verify(storage).prepareStatement(captor.capture()); - StatementDescriptor<VmDeadLockData> desc = captor.getValue(); - assertEquals(ThreadDaoImpl.DESC_ADD_THREAD_DEADLOCK_DATA, desc.getDescriptor()); - - verify(add).setString(0, status.getAgentId()); - verify(add).setString(1, status.getVmId()); - verify(add).setLong(2, status.getTimeStamp()); - verify(add).setString(3, status.getDeadLockDescription()); - verify(add).execute(); - Mockito.verifyNoMoreInteractions(add); - } - - @Test - public void testGetLatestHarvestingStatus() - throws DescriptorParsingException, StatementExecutionException { - Storage storage = mock(Storage.class); - @SuppressWarnings("unchecked") - PreparedStatement<ThreadHarvestingStatus> stmt = (PreparedStatement<ThreadHarvestingStatus>) mock(PreparedStatement.class); - when(storage.prepareStatement(anyDescriptor(ThreadHarvestingStatus.class))).thenReturn(stmt); - @SuppressWarnings("unchecked") - Cursor<ThreadHarvestingStatus> cursor = (Cursor<ThreadHarvestingStatus>) mock(Cursor.class); - ThreadHarvestingStatus status = mock(ThreadHarvestingStatus.class); - - when(cursor.hasNext()).thenReturn(true); - when(cursor.next()).thenReturn(status); - when(stmt.executeQuery()).thenReturn(cursor); - - ThreadDaoImpl dao = new ThreadDaoImpl(storage); - ThreadHarvestingStatus result = dao.getLatestHarvestingStatus(vmRef); - - verify(storage).prepareStatement(anyDescriptor(ThreadHarvestingStatus.class)); - verify(stmt).setString(0, AGENT_ID); - verify(stmt).setString(1, VM_ID); - verify(stmt).executeQuery(); - verifyNoMoreInteractions(stmt); - - assertSame(status, result); - } - - @SuppressWarnings("unchecked") - @Test - public void testAddHarvestingStatus() throws DescriptorParsingException, StatementExecutionException { - Storage storage = mock(Storage.class); - PreparedStatement<ThreadHarvestingStatus> add = mock(PreparedStatement.class); - when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add); - - ThreadHarvestingStatus status = mock(ThreadHarvestingStatus.class); - - ThreadDaoImpl dao = new ThreadDaoImpl(storage); - dao.saveHarvestingStatus(status); - - @SuppressWarnings("rawtypes") - ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class); - - verify(storage).prepareStatement(captor.capture()); - StatementDescriptor<VmDeadLockData> desc = captor.getValue(); - assertEquals(ThreadDaoImpl.DESC_ADD_THREAD_HARVESTING_STATUS, desc.getDescriptor()); - - verify(add).setString(0, status.getAgentId()); - verify(add).setString(1, status.getVmId()); - verify(add).setLong(2, status.getTimeStamp()); - verify(add).setBoolean(3, status.isHarvesting()); - verify(add).execute(); - verifyNoMoreInteractions(add); - } - -} -
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/SessionQueriesTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl.statement; - -import com.redhat.thermostat.storage.core.experimental.statement.BeanAdapter; -import com.redhat.thermostat.storage.core.experimental.statement.BeanAdapterBuilder; -import com.redhat.thermostat.thread.model.ThreadSession; -import java.util.Set; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class SessionQueriesTest { - - @Test - public void testDescribe() throws Exception { - BeanAdapter<ThreadSession> session = - new BeanAdapterBuilder<>(ThreadSession.class, - SessionQueries.asList()).build(); - Set<String> statements = session.describeStatements(); - assertEquals(3, statements.size()); - - String expected = "QUERY vm-thread-session WHERE 'vmId' = ?s AND 'agentId' = ?s AND 'timeStamp' >= ?l AND 'timeStamp' <= ?l SORT 'timeStamp' ASC LIMIT ?i"; - assertTrue(statements.contains(expected)); - - expected = "QUERY vm-thread-session WHERE 'vmId' = ?s AND 'agentId' = ?s AND 'timeStamp' >= ?l AND 'timeStamp' <= ?l SORT 'timeStamp' DSC LIMIT ?i"; - assertTrue(statements.contains(expected)); - } -}
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/statement/SummaryQueryTest.java Wed Apr 06 14:52:26 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * Copyright 2012-2016 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.thread.dao.impl.statement; - -import com.redhat.thermostat.storage.core.experimental.statement.BeanAdapter; -import com.redhat.thermostat.storage.core.experimental.statement.BeanAdapterBuilder; -import com.redhat.thermostat.thread.model.ThreadSummary; -import java.util.Set; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class SummaryQueryTest { - @Test - public void testDescribe() throws Exception { - BeanAdapter<ThreadSummary> session = - new BeanAdapterBuilder<>(ThreadSummary.class, - new SummaryQuery()).build(); - Set<String> statements = session.describeStatements(); - assertEquals(2, statements.size()); - - String expected = "QUERY vm-thread-summary WHERE 'vmId' = ?s AND 'agentId' = ?s AND 'timeStamp' >= ?l AND 'timeStamp' <= ?l SORT 'timeStamp' DSC LIMIT ?i"; - assertTrue(statements.contains(expected)); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/internal/LockInfoDaoCategoryRegistrationTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.Set; + +import org.junit.Test; + +import com.redhat.thermostat.storage.core.auth.CategoryRegistration; +import com.redhat.thermostat.testutils.ServiceLoaderTest; + +public class LockInfoDaoCategoryRegistrationTest extends ServiceLoaderTest<CategoryRegistration> { + + public LockInfoDaoCategoryRegistrationTest() { + super(CategoryRegistration.class, STORAGE_SERVICES + 1, /* from TheadDao */ + LockInfoDaoCategoryRegistration.class); + } + + @Test + public void verifyKnownsCategory() { + Set<String> names = + new LockInfoDaoCategoryRegistration().getCategoryNames(); + assertEquals(1, names.size()); + assertTrue(names.contains("vm-thread-lock")); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/internal/LockInfoDaoImplStatementDescriptorRegistrationTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal; + +import static org.junit.Assert.assertEquals; + +import java.util.Set; + +import org.junit.Test; + +import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; +import com.redhat.thermostat.testutils.ServiceLoaderTest; + +public class LockInfoDaoImplStatementDescriptorRegistrationTest extends ServiceLoaderTest<StatementDescriptorRegistration> { + + public LockInfoDaoImplStatementDescriptorRegistrationTest() { + super(StatementDescriptorRegistration.class, STORAGE_SERVICES + 1 /* from thread dao */, LockInfoDaoImplStatementDescriptorRegistration.class); + } + + @Test + public void verifyExportsStatements() { + Set<String> statements = + new LockInfoDaoImplStatementDescriptorRegistration().getStatementDescriptors(); + + assertEquals(3, statements.size()); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/internal/ThreadDAOCategoryRegistrationTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,82 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.Test; + +import com.redhat.thermostat.storage.core.auth.CategoryRegistration; +import com.redhat.thermostat.testutils.ServiceLoaderTest; +import com.redhat.thermostat.thread.dao.ThreadDao; + +public class ThreadDAOCategoryRegistrationTest extends ServiceLoaderTest<CategoryRegistration> { + + private static final int EXPECTED_CATEGORIES = 6; + + public ThreadDAOCategoryRegistrationTest() { + super(CategoryRegistration.class, STORAGE_SERVICES + 1 /* from lock dao */, + ThreadDAOCategoryRegistration.class); + } + + @Test + public void registersAllCategories() { + ThreadDAOCategoryRegistration reg = new ThreadDAOCategoryRegistration(); + Set<String> categories = reg.getCategoryNames(); + assertEquals(EXPECTED_CATEGORIES, categories.size()); + + assertFalse("null descriptor not allowed", categories.contains(null)); + + assertTrue(categories.contains(ThreadDao.DEADLOCK_INFO.getName())); + assertTrue(categories.contains(ThreadDao.THREAD_HARVESTING_STATUS.getName())); + assertTrue(categories.contains(ThreadDao.THREAD_CONTENTION_SAMPLE.getName())); + + Set<String> sourceCategories = new HashSet<>(); + ThreadDaoCategories.register(sourceCategories); + + for (String category : sourceCategories) { + assertTrue(categories.contains(category)); + } + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoCategoriesTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,85 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.junit.Test; + +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.core.experimental.statement.Category; +import com.redhat.thermostat.storage.core.experimental.statement.CategoryBuilder; +import com.redhat.thermostat.storage.model.Pojo; + +public class ThreadDaoCategoriesTest { + + @Test + public void testRegister() throws Exception { + Set<String> set = new HashSet<>(); + ThreadDaoCategories.register(set); + + assertEquals(ThreadDaoCategories.BEANS.size(), set.size()); + for (Class<? extends Pojo> categoryClass : ThreadDaoCategories.BEANS) { + String name = categoryClass.getAnnotation(Category.class).value(); + assertTrue(set.contains(name)); + } + } + + @Test + public void testRegisterInStorage() throws Exception { + Storage storage = mock(Storage.class); + + List<com.redhat.thermostat.storage.core.Category<?>> categories = + new ArrayList<>(); + for (Class<? extends Pojo> categoryClass : ThreadDaoCategories.BEANS) { + categories.add(new CategoryBuilder(categoryClass).build()); + } + + ThreadDaoCategories.register(storage); + for (com.redhat.thermostat.storage.core.Category<?> category : categories) { + verify(storage).registerCategory(category); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoImplStatementDescriptorRegistrationTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import java.util.Set; + +import org.junit.Test; + +import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; +import com.redhat.thermostat.testutils.ServiceLoaderTest; + +public class ThreadDaoImplStatementDescriptorRegistrationTest extends ServiceLoaderTest<StatementDescriptorRegistration> { + + public ThreadDaoImplStatementDescriptorRegistrationTest() { + super(StatementDescriptorRegistration.class, STORAGE_SERVICES + 1 /* from lock dao */, ThreadDaoImplStatementDescriptorRegistration.class); + } + + @Test + public void registersAllDescriptors() { + ThreadDaoImplStatementDescriptorRegistration reg = new ThreadDaoImplStatementDescriptorRegistration(); + Set<String> descriptors = reg.getStatementDescriptors(); + assertEquals(14, descriptors.size()); + assertFalse("null statement not allowed", descriptors.contains(null)); + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/internal/ThreadDaoImplTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,263 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.mockito.Matchers.any; +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 org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import com.redhat.thermostat.storage.core.Cursor; +import com.redhat.thermostat.storage.core.DescriptorParsingException; +import com.redhat.thermostat.storage.core.HostRef; +import com.redhat.thermostat.storage.core.PreparedStatement; +import com.redhat.thermostat.storage.core.StatementDescriptor; +import com.redhat.thermostat.storage.core.StatementExecutionException; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.model.Pojo; +import com.redhat.thermostat.thread.dao.ThreadDao; +import com.redhat.thermostat.thread.model.ThreadHarvestingStatus; +import com.redhat.thermostat.thread.model.VmDeadLockData; + +public class ThreadDaoImplTest { + + private static final String AGENT_ID = "0xcafe"; + private static final String VM_ID = "VM42"; + + private VmRef vmRef; + private HostRef hostRef; + + @Before + public void setUp() { + hostRef = mock(HostRef.class); + when(hostRef.getAgentId()).thenReturn(AGENT_ID); + + vmRef = mock(VmRef.class); + when(vmRef.getHostRef()).thenReturn(hostRef); + when(vmRef.getVmId()).thenReturn(VM_ID); + } + + @Test + public void preparedQueryDescriptorsAreSane() { + + String expectedQueryLatestHarvestingStatus = "QUERY vm-thread-harvesting WHERE 'agentId' = ?s AND 'vmId' = ?s SORT 'timeStamp' DSC LIMIT 1"; + assertEquals(expectedQueryLatestHarvestingStatus, ThreadDaoImpl.QUERY_LATEST_HARVESTING_STATUS); + + String expectedQueryThreadLatestDeadlockInfo = "QUERY vm-deadlock-data WHERE 'agentId' = ?s AND 'vmId' = ?s SORT 'timeStamp' DSC LIMIT 1"; + assertEquals(expectedQueryThreadLatestDeadlockInfo, ThreadDaoImpl.QUERY_LATEST_DEADLOCK_INFO); + + String addThreadHarvesting = "ADD vm-thread-harvesting SET 'agentId' = ?s , " + + "'vmId' = ?s , " + + "'timeStamp' = ?l , " + + "'harvesting' = ?b"; + assertEquals(addThreadHarvesting, ThreadDaoImpl.DESC_ADD_THREAD_HARVESTING_STATUS); + + String addThreadInfo = "ADD vm-thread-header SET 'agentId' = ?s , " + + "'vmId' = ?s , " + + "'threadName' = ?s , " + + "'threadId' = ?l , " + + "'timeStamp' = ?l , " + + "'referenceID' = ?s"; + + String addContentionSample = "ADD thread-contention-sample SET " + + "'agentId' = ?s , 'vmId' = ?s , 'blockedCount' = ?l , " + + "'blockedTime' = ?l , 'waitedCount' = ?l , " + + "'waitedTime' = ?l , 'referenceID' = ?s , 'timeStamp' = ?l"; + assertEquals(addContentionSample, ThreadDaoImpl.ADD_CONTENTION_SAMPLE); + + String getLatestContentionSample = "QUERY thread-contention-sample " + + "WHERE 'referenceID' = ?s SORT 'timeStamp' DSC LIMIT 1"; + assertEquals(getLatestContentionSample, ThreadDaoImpl.GET_LATEST_CONTENTION_SAMPLE); + + String getFirstThreadState = "QUERY vm-thread-state WHERE " + + "'agentId' = ?s AND 'referenceID' = ?s SORT 'probeStartTime' " + + "ASC LIMIT 1"; + } + + @Test + public void testThreadDaoCategoryRegistration() { + Storage storage = mock(Storage.class); + + @SuppressWarnings("unused") + ThreadDaoImpl dao = new ThreadDaoImpl(storage); + + verify(storage).registerCategory(ThreadDao.THREAD_HARVESTING_STATUS); + } + + @SuppressWarnings("unchecked") + private <T extends Pojo> StatementDescriptor<T> anyDescriptor(Class<T> type) { + return (StatementDescriptor<T>) any(StatementDescriptor.class); + } + + @Test + public void testLoadLatestDeadLockStatusWithNoData() throws Exception { + Storage storage = mock(Storage.class); + @SuppressWarnings("unchecked") + PreparedStatement<VmDeadLockData> stmt = (PreparedStatement<VmDeadLockData>) mock(PreparedStatement.class); + when(storage.prepareStatement(anyDescriptor(VmDeadLockData.class))).thenReturn(stmt); + @SuppressWarnings("unchecked") + Cursor<VmDeadLockData> cursor = (Cursor<VmDeadLockData>) mock(Cursor.class); + + when(cursor.hasNext()).thenReturn(false); + when(cursor.next()).thenThrow(new IllegalStateException("must not do this")); + when(stmt.executeQuery()).thenReturn(cursor); + + ThreadDaoImpl dao = new ThreadDaoImpl(storage); + VmDeadLockData result = dao.loadLatestDeadLockStatus(vmRef); + + assertNull(result); + } + + @Test + public void testLoadLatestDeadLockStatus() throws DescriptorParsingException, StatementExecutionException { + Storage storage = mock(Storage.class); + @SuppressWarnings("unchecked") + PreparedStatement<VmDeadLockData> stmt = (PreparedStatement<VmDeadLockData>) mock(PreparedStatement.class); + when(storage.prepareStatement(anyDescriptor(VmDeadLockData.class))).thenReturn(stmt); + @SuppressWarnings("unchecked") + Cursor<VmDeadLockData> cursor = (Cursor<VmDeadLockData>) mock(Cursor.class); + VmDeadLockData data = mock(VmDeadLockData.class); + + when(cursor.hasNext()).thenReturn(true); + when(cursor.next()).thenReturn(data); + when(stmt.executeQuery()).thenReturn(cursor); + + ThreadDaoImpl dao = new ThreadDaoImpl(storage); + VmDeadLockData result = dao.loadLatestDeadLockStatus(vmRef); + + assertSame(data, result); + + verify(storage).prepareStatement(anyDescriptor(VmDeadLockData.class)); + verify(stmt).setString(0, AGENT_ID); + verify(stmt).setString(1, VM_ID); + verify(stmt).executeQuery(); + verifyNoMoreInteractions(stmt); + } + + @SuppressWarnings("unchecked") + @Test + public void testSaveDeadLockStatus() throws DescriptorParsingException, StatementExecutionException { + Storage storage = mock(Storage.class); + PreparedStatement<VmDeadLockData> add = mock(PreparedStatement.class); + when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add); + + VmDeadLockData status = mock(VmDeadLockData.class); + + ThreadDaoImpl dao = new ThreadDaoImpl(storage); + dao.saveDeadLockStatus(status); + + @SuppressWarnings("rawtypes") + ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class); + + verify(storage).prepareStatement(captor.capture()); + StatementDescriptor<VmDeadLockData> desc = captor.getValue(); + assertEquals(ThreadDaoImpl.DESC_ADD_THREAD_DEADLOCK_DATA, desc.getDescriptor()); + + verify(add).setString(0, status.getAgentId()); + verify(add).setString(1, status.getVmId()); + verify(add).setLong(2, status.getTimeStamp()); + verify(add).setString(3, status.getDeadLockDescription()); + verify(add).execute(); + Mockito.verifyNoMoreInteractions(add); + } + + @Test + public void testGetLatestHarvestingStatus() + throws DescriptorParsingException, StatementExecutionException { + Storage storage = mock(Storage.class); + @SuppressWarnings("unchecked") + PreparedStatement<ThreadHarvestingStatus> stmt = (PreparedStatement<ThreadHarvestingStatus>) mock(PreparedStatement.class); + when(storage.prepareStatement(anyDescriptor(ThreadHarvestingStatus.class))).thenReturn(stmt); + @SuppressWarnings("unchecked") + Cursor<ThreadHarvestingStatus> cursor = (Cursor<ThreadHarvestingStatus>) mock(Cursor.class); + ThreadHarvestingStatus status = mock(ThreadHarvestingStatus.class); + + when(cursor.hasNext()).thenReturn(true); + when(cursor.next()).thenReturn(status); + when(stmt.executeQuery()).thenReturn(cursor); + + ThreadDaoImpl dao = new ThreadDaoImpl(storage); + ThreadHarvestingStatus result = dao.getLatestHarvestingStatus(vmRef); + + verify(storage).prepareStatement(anyDescriptor(ThreadHarvestingStatus.class)); + verify(stmt).setString(0, AGENT_ID); + verify(stmt).setString(1, VM_ID); + verify(stmt).executeQuery(); + verifyNoMoreInteractions(stmt); + + assertSame(status, result); + } + + @SuppressWarnings("unchecked") + @Test + public void testAddHarvestingStatus() throws DescriptorParsingException, StatementExecutionException { + Storage storage = mock(Storage.class); + PreparedStatement<ThreadHarvestingStatus> add = mock(PreparedStatement.class); + when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add); + + ThreadHarvestingStatus status = mock(ThreadHarvestingStatus.class); + + ThreadDaoImpl dao = new ThreadDaoImpl(storage); + dao.saveHarvestingStatus(status); + + @SuppressWarnings("rawtypes") + ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class); + + verify(storage).prepareStatement(captor.capture()); + StatementDescriptor<VmDeadLockData> desc = captor.getValue(); + assertEquals(ThreadDaoImpl.DESC_ADD_THREAD_HARVESTING_STATUS, desc.getDescriptor()); + + verify(add).setString(0, status.getAgentId()); + verify(add).setString(1, status.getVmId()); + verify(add).setLong(2, status.getTimeStamp()); + verify(add).setBoolean(3, status.isHarvesting()); + verify(add).execute(); + verifyNoMoreInteractions(add); + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/internal/statement/SessionQueriesTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,66 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal.statement; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.Set; + +import org.junit.Test; + +import com.redhat.thermostat.storage.core.experimental.statement.BeanAdapter; +import com.redhat.thermostat.storage.core.experimental.statement.BeanAdapterBuilder; +import com.redhat.thermostat.thread.model.ThreadSession; + +public class SessionQueriesTest { + + @Test + public void testDescribe() throws Exception { + BeanAdapter<ThreadSession> session = + new BeanAdapterBuilder<>(ThreadSession.class, + SessionQueries.asList()).build(); + Set<String> statements = session.describeStatements(); + assertEquals(3, statements.size()); + + String expected = "QUERY vm-thread-session WHERE 'vmId' = ?s AND 'agentId' = ?s AND 'timeStamp' >= ?l AND 'timeStamp' <= ?l SORT 'timeStamp' ASC LIMIT ?i"; + assertTrue(statements.contains(expected)); + + expected = "QUERY vm-thread-session WHERE 'vmId' = ?s AND 'agentId' = ?s AND 'timeStamp' >= ?l AND 'timeStamp' <= ?l SORT 'timeStamp' DSC LIMIT ?i"; + assertTrue(statements.contains(expected)); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/internal/statement/SummaryQueryTest.java Fri Apr 08 13:18:48 2016 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright 2012-2016 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.thread.dao.internal.statement; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.Set; + +import org.junit.Test; + +import com.redhat.thermostat.storage.core.experimental.statement.BeanAdapter; +import com.redhat.thermostat.storage.core.experimental.statement.BeanAdapterBuilder; +import com.redhat.thermostat.thread.model.ThreadSummary; + +public class SummaryQueryTest { + @Test + public void testDescribe() throws Exception { + BeanAdapter<ThreadSummary> session = + new BeanAdapterBuilder<>(ThreadSummary.class, + new SummaryQuery()).build(); + Set<String> statements = session.describeStatements(); + assertEquals(2, statements.size()); + + String expected = "QUERY vm-thread-summary WHERE 'vmId' = ?s AND 'agentId' = ?s AND 'timeStamp' >= ?l AND 'timeStamp' <= ?l SORT 'timeStamp' DSC LIMIT ?i"; + assertTrue(statements.contains(expected)); + } +}