Mercurial > hg > release > thermostat-0.4
changeset 576:4fbe27356f96
Merge
author | Roman Kennke <rkennke@redhat.com> |
---|---|
date | Fri, 31 Aug 2012 11:26:14 +0200 |
parents | 0375b44c73d4 (current diff) 06f2dcf9ad3b (diff) |
children | d03acb3cf6c6 |
files | common/core/src/test/java/com/redhat/thermostat/common/dao/HeapDAOTest.java distribution/config/bundles.properties distribution/pom.xml thread/collector/src/main/java/com/redhat/thermostat/thread/collector/ThreadCollector.java thread/collector/src/main/java/com/redhat/thermostat/thread/collector/ThreadCollectorFactory.java thread/collector/src/main/java/com/redhat/thermostat/thread/collector/ThreadInfo.java thread/collector/src/main/java/com/redhat/thermostat/thread/collector/ThreadSummary.java thread/collector/src/main/java/com/redhat/thermostat/thread/collector/VMThreadCapabilities.java thread/collector/src/main/java/com/redhat/thermostat/thread/collector/impl/ThreadCollectorFactoryImpl.java thread/collector/src/main/java/com/redhat/thermostat/thread/collector/impl/ThreadMXBeanCollector.java thread/collector/src/main/java/com/redhat/thermostat/thread/collector/impl/ThreadMXInfo.java thread/collector/src/main/java/com/redhat/thermostat/thread/collector/impl/ThreadMXSummary.java thread/collector/src/main/java/com/redhat/thermostat/thread/collector/impl/VMThreadMXCapabilities.java thread/collector/src/main/java/com/redhat/thermostat/thread/collector/osgi/Activator.java thread/collector/src/main/java/com/redhat/thermostat/utils/management/MXBeanConnection.java thread/collector/src/main/java/com/redhat/thermostat/utils/management/MXBeanConnector.java thread/collector/src/test/java/com/redhat/thermostat/thread/collector/ThreadCollectorFactoryTest.java thread/collector/src/test/java/com/redhat/thermostat/thread/collector/ThreadCollectorTest.java |
diffstat | 75 files changed, 2841 insertions(+), 1696 deletions(-) [+] |
line wrap: on
line diff
--- a/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/AgentApplication.java Fri Aug 31 11:22:52 2012 +0200 +++ b/agent/cli/src/main/java/com/redhat/thermostat/agent/cli/AgentApplication.java Fri Aug 31 11:26:14 2012 +0200 @@ -64,6 +64,7 @@ import com.redhat.thermostat.common.storage.Connection.ConnectionListener; import com.redhat.thermostat.common.storage.Connection.ConnectionStatus; import com.redhat.thermostat.common.storage.MongoStorageProvider; +import com.redhat.thermostat.common.storage.Storage; import com.redhat.thermostat.common.storage.StorageProvider; import com.redhat.thermostat.common.tools.BasicCommand; import com.redhat.thermostat.common.utils.LoggingUtils; @@ -106,7 +107,7 @@ final Logger logger = LoggingUtils.getLogger(AgentApplication.class); StorageProvider connProv = new MongoStorageProvider(configuration); - DAOFactory daoFactory = new MongoDAOFactory(connProv); + final DAOFactory daoFactory = new MongoDAOFactory(connProv); ApplicationContext.getInstance().setDAOFactory(daoFactory); TimerFactory timerFactory = new ThreadPoolTimerFactory(1); ApplicationContext.getInstance().setTimerFactory(timerFactory); @@ -123,7 +124,9 @@ logger.fine("Connecting to storage."); break; case CONNECTED: - logger.fine("Connected to storage."); + logger.fine("Connected to storage, registering storage as service"); + Storage storage = daoFactory.getStorage(); + OSGIUtils.getInstance().registerService(Storage.class, storage); break; case FAILED_TO_CONNECT: logger.warning("Could not connect to storage.");
--- a/agent/command/src/main/java/com/redhat/thermostat/agent/command/ReceiverRegistry.java Fri Aug 31 11:22:52 2012 +0200 +++ b/agent/command/src/main/java/com/redhat/thermostat/agent/command/ReceiverRegistry.java Fri Aug 31 11:26:14 2012 +0200 @@ -60,3 +60,4 @@ proxy.unregisterAll(); } } +
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/Chunk.java Fri Aug 31 11:22:52 2012 +0200 +++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/Chunk.java Fri Aug 31 11:26:14 2012 +0200 @@ -100,4 +100,9 @@ return Objects.equals(this.category, other.category) && Objects.equals(this.values, other.values); } + @Override + public String toString() { + return "Chunk: " + category.getName() + values.toString(); + } + }
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/Key.java Fri Aug 31 11:22:52 2012 +0200 +++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/Key.java Fri Aug 31 11:26:14 2012 +0200 @@ -44,8 +44,8 @@ // Keys used by most Categories. public static final Key<Long> TIMESTAMP = new Key<>("timestamp", false); - public static final Key<String> AGENT_ID = new Key<>("agent-id", false); - public static final Key<Integer> VM_ID = new Key<>("vm-id", false); + public static final Key<String> AGENT_ID = new Key<>("agent-id", true); + public static final Key<Integer> VM_ID = new Key<>("vm-id", true); public static final Key<String> WHERE = new Key<>("$where", false); public static final Key<String> ID = new Key<>("_id", false);
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java Fri Aug 31 11:22:52 2012 +0200 +++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java Fri Aug 31 11:26:14 2012 +0200 @@ -141,7 +141,7 @@ BasicDBObject nested = nestedParts.get(entryParts[0]); if (nested == null) { if (isKey) { - throwMissingKey(key.getName()); + throwMissingKey(key.getName(), chunk); } nested = new BasicDBObject(); nestedParts.put(entryParts[0], nested); @@ -156,11 +156,12 @@ replaceKeyNested.append(entryParts[1], replaceKeyNested); } } else { + /* we dont modify agent id, and it's already used as key in updateKey */ if (!key.equals(Key.AGENT_ID)) { String mongoKey = key.getName(); Object value = chunk.get(key); if ((value == null) && isKey) { - throwMissingKey(key.getName()); + throwMissingKey(key.getName(), chunk); } toInsert.append(mongoKey, value); if (replace && isKey) { @@ -197,7 +198,7 @@ BasicDBObject nested = nestedParts.get(entryParts[0]); if (nested == null) { if (isKey) { - throwMissingKey(key.getName()); + throwMissingKey(key.getName(), chunk); } } else { if (isKey) { @@ -213,16 +214,19 @@ } } else { String mongoKey = key.getName(); - Object value = chunk.get(key); - if (value == null) { - if (isKey) { - throwMissingKey(key.getName()); - } - } else { - if (isKey) { - updateKey.append(mongoKey, value); + /* we dont modify agent id, and it's already used as key in updateKey */ + if (!key.equals(Key.AGENT_ID)) { + Object value = chunk.get(key); + if (value == null) { + if (isKey) { + throwMissingKey(key.getName(), chunk); + } } else { - toUpdate.append(SET_MODIFIER, new BasicDBObject(mongoKey, value)); + if (isKey) { + updateKey.append(mongoKey, value); + } else { + toUpdate.append(SET_MODIFIER, new BasicDBObject(mongoKey, value)); + } } } } @@ -236,8 +240,8 @@ coll.update(updateKey, toUpdate); } - private void throwMissingKey(String keyName) { - throw new IllegalArgumentException("Attempt to insert chunk with incomplete partial key. Missing: " + keyName); + private void throwMissingKey(String keyName, Chunk chunk) { + throw new IllegalArgumentException("Attempt to insert chunk with incomplete partial key. Missing: '" + keyName + "' in " + chunk); } private DBCollection getCachedCollection(String collName) {
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/CpuStatDAOTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/CpuStatDAOTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -67,7 +67,7 @@ public void testCategory() { assertEquals("cpu-stats", CpuStatDAO.cpuStatCategory.getName()); Collection<Key<?>> keys = CpuStatDAO.cpuStatCategory.getKeys(); - assertTrue(keys.contains(new Key<>("agent-id", false))); + assertTrue(keys.contains(new Key<>("agent-id", true))); assertTrue(keys.contains(new Key<Long>("timestamp", false))); assertTrue(keys.contains(new Key<Double>("processor-usage", false)));
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/HeapDAOTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/HeapDAOTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -189,8 +189,8 @@ Collection<Key<?>> keys = category.getKeys(); assertEquals(6, keys.size()); assertTrue(keys.contains(new Key<>("_id", false))); - assertTrue(keys.contains(new Key<>("agent-id", false))); - assertTrue(keys.contains(new Key<>("vm-id", false))); + assertTrue(keys.contains(new Key<>("agent-id", true))); + assertTrue(keys.contains(new Key<>("vm-id", true))); assertTrue(keys.contains(new Key<>("timestamp", false))); assertTrue(keys.contains(new Key<>("heap-dump-id", false))); assertTrue(keys.contains(new Key<>("histogram-id", false)));
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/HostInfoDAOTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/HostInfoDAOTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -72,7 +72,7 @@ public void testCategory() { assertEquals("host-info", HostInfoDAO.hostInfoCategory.getName()); Collection<Key<?>> keys = HostInfoDAO.hostInfoCategory.getKeys(); - assertTrue(keys.contains(new Key<>("agent-id", false))); + assertTrue(keys.contains(new Key<>("agent-id", true))); assertTrue(keys.contains(new Key<String>("hostname", true))); assertTrue(keys.contains(new Key<String>("os_name", false))); assertTrue(keys.contains(new Key<String>("os_kernel", false)));
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/MemoryStatDAOTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/MemoryStatDAOTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -74,7 +74,7 @@ public void testCategory() { assertEquals("memory-stats", MemoryStatDAO.memoryStatCategory.getName()); Collection<Key<?>> keys = MemoryStatDAO.memoryStatCategory.getKeys(); - assertTrue(keys.contains(new Key<>("agent-id", false))); + assertTrue(keys.contains(new Key<>("agent-id", true))); assertTrue(keys.contains(new Key<Long>("timestamp", false))); assertTrue(keys.contains(new Key<Long>("total", false))); assertTrue(keys.contains(new Key<Long>("free", false)));
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/NetworkInterfaceInfoDAOTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -69,7 +69,7 @@ assertEquals("network-info", NetworkInterfaceInfoDAO.networkInfoCategory.getName()); keys = NetworkInterfaceInfoDAO.networkInfoCategory.getKeys(); - assertTrue(keys.contains(new Key<>("agent-id", false))); + assertTrue(keys.contains(new Key<>("agent-id", true))); assertTrue(keys.contains(new Key<Long>("timestamp", false))); assertTrue(keys.contains(new Key<String>("iface", true))); assertTrue(keys.contains(new Key<String>("ipv4addr", false)));
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmClassStatConverterTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmClassStatConverterTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -55,7 +55,7 @@ assertEquals("vm-class-stats", chunk.getCategory().getName()); assertEquals((Long) 1234L, chunk.get(Key.TIMESTAMP)); - assertEquals((Integer) 123, chunk.get(new Key<Integer>("vm-id", false))); + assertEquals((Integer) 123, chunk.get(new Key<Integer>("vm-id", true))); assertEquals((Long) 12345L, chunk.get(new Key<Long>("loadedClasses", false))); }
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmClassStatDAOTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmClassStatDAOTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -67,8 +67,8 @@ public void testCategory() { assertEquals("vm-class-stats", VmClassStatDAO.vmClassStatsCategory.getName()); Collection<Key<?>> keys = VmClassStatDAO.vmClassStatsCategory.getKeys(); - assertTrue(keys.contains(new Key<>("agent-id", false))); - assertTrue(keys.contains(new Key<Integer>("vm-id", false))); + assertTrue(keys.contains(new Key<>("agent-id", true))); + assertTrue(keys.contains(new Key<Integer>("vm-id", true))); assertTrue(keys.contains(new Key<Long>("timestamp", false))); assertTrue(keys.contains(new Key<Long>("loadedClasses", false))); assertEquals(4, keys.size());
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmCpuStatConverterTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmCpuStatConverterTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -58,7 +58,7 @@ assertNotNull(chunk); assertEquals("vm-cpu-stats", chunk.getCategory().getName()); assertEquals((Long)TIMESTAMP, chunk.get(Key.TIMESTAMP)); - assertEquals((Integer) VM_ID, chunk.get(new Key<Long>("vm-id", false))); + assertEquals((Integer) VM_ID, chunk.get(new Key<Long>("vm-id", true))); assertEquals(PROCESSOR_USAGE, chunk.get(new Key<Double>("processor-usage", false)), 0.001); }
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmCpuStatDAOTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmCpuStatDAOTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -80,9 +80,9 @@ public void testCategory() { assertEquals("vm-cpu-stats", VmCpuStatDAO.vmCpuStatCategory.getName()); Collection<Key<?>> keys = VmCpuStatDAO.vmCpuStatCategory.getKeys(); - assertTrue(keys.contains(new Key<>("agent-id", false))); + assertTrue(keys.contains(new Key<>("agent-id", true))); assertTrue(keys.contains(new Key<Long>("timestamp", false))); - assertTrue(keys.contains(new Key<Integer>("vm-id", false))); + assertTrue(keys.contains(new Key<Integer>("vm-id", true))); assertTrue(keys.contains(new Key<Integer>("processor-usage", false))); assertEquals(4, keys.size()); }
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmGcStatConverterTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmGcStatConverterTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -60,7 +60,7 @@ assertNotNull(chunk); assertEquals("vm-gc-stats", chunk.getCategory().getName()); assertEquals(TIMESTAMP, chunk.get(new Key<Long>("timestamp", false))); - assertEquals(VM_ID, chunk.get(new Key<Integer>("vm-id", false))); + assertEquals(VM_ID, chunk.get(new Key<Integer>("vm-id", true))); assertEquals(COLLECTOR, chunk.get(new Key<String>("collector", false))); assertEquals(RUN_COUNT, chunk.get(new Key<Long>("runtime-count", false))); assertEquals(WALL_TIME, chunk.get(new Key<Long>("wall-time", false)));
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmGcStatDAOTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmGcStatDAOTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -70,8 +70,8 @@ public void testCategory() { assertEquals("vm-gc-stats", VmGcStatDAO.vmGcStatCategory.getName()); Collection<Key<?>> keys = VmGcStatDAO.vmGcStatCategory.getKeys(); - assertTrue(keys.contains(new Key<>("agent-id", false))); - assertTrue(keys.contains(new Key<Integer>("vm-id", false))); + assertTrue(keys.contains(new Key<>("agent-id", true))); + assertTrue(keys.contains(new Key<Integer>("vm-id", true))); assertTrue(keys.contains(new Key<Long>("timestamp", false))); assertTrue(keys.contains(new Key<String>("collector", false))); assertTrue(keys.contains(new Key<Long>("runtime-count", false)));
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmInfoDAOTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmInfoDAOTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -109,7 +109,7 @@ public void testCategory() { assertEquals("vm-info", VmInfoDAO.vmInfoCategory.getName()); Collection<Key<?>> keys = VmInfoDAO.vmInfoCategory.getKeys(); - assertTrue(keys.contains(new Key<>("agent-id", false))); + assertTrue(keys.contains(new Key<>("agent-id", true))); assertTrue(keys.contains(new Key<Integer>("vm-id", true))); assertTrue(keys.contains(new Key<Integer>("vm-pid", false))); assertTrue(keys.contains(new Key<String>("runtime-version", false)));
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmMemoryStatConverterTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmMemoryStatConverterTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -88,7 +88,7 @@ assertNotNull(chunk); assertEquals((Long) 1l, chunk.get(new Key<Long>("timestamp", false))); - assertEquals((Integer) 2, chunk.get(new Key<Integer>("vm-id", false))); + assertEquals((Integer) 2, chunk.get(new Key<Integer>("vm-id", true))); assertEquals("new", chunk.get(new Key<String>("eden.gen", false))); assertEquals("new", chunk.get(new Key<String>("eden.collector", false))); assertEquals((Long) 0l, chunk.get(new Key<Long>("eden.used", false)));
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmMemoryStatDAOTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmMemoryStatDAOTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -116,8 +116,8 @@ assertEquals("vm-memory-stats", VmMemoryStatDAO.vmMemoryStatsCategory.getName()); keys = VmMemoryStatDAO.vmMemoryStatsCategory.getKeys(); - assertTrue(keys.contains(new Key<>("agent-id", false))); - assertTrue(keys.contains(new Key<Integer>("vm-id", false))); + assertTrue(keys.contains(new Key<>("agent-id", true))); + assertTrue(keys.contains(new Key<Integer>("vm-id", true))); assertTrue(keys.contains(new Key<Long>("timestamp", false))); assertTrue(keys.contains(new Key<String>("eden.gen", false))); assertTrue(keys.contains(new Key<String>("eden.collector", false))); @@ -234,7 +234,7 @@ assertEquals(VmMemoryStatDAO.vmMemoryStatsCategory, chunk.getCategory()); assertEquals((Long) 1l, chunk.get(new Key<Long>("timestamp", false))); - assertEquals((Integer) 2, chunk.get(new Key<Integer>("vm-id", false))); + assertEquals((Integer) 2, chunk.get(new Key<Integer>("vm-id", true))); assertEquals("new", chunk.get(new Key<String>("eden.gen", false))); assertEquals("new", chunk.get(new Key<String>("eden.collector", false))); assertEquals((Long) 0l, chunk.get(new Key<Long>("eden.used", false)));
--- a/common/core/src/test/java/com/redhat/thermostat/common/storage/KeyTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/common/core/src/test/java/com/redhat/thermostat/common/storage/KeyTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -130,4 +130,14 @@ String string1 = key1.toString(); assertEquals(string1, "Key: key1"); } + + @Test + public void verifyAgentIdIsPartialkey() { + assertTrue(Key.AGENT_ID.isPartialCategoryKey()); + } + + @Test + public void verifyVmIdIsPartialkey() { + assertTrue(Key.VM_ID.isPartialCategoryKey()); + } }
--- a/distribution/config/bundles.properties Fri Aug 31 11:22:52 2012 +0200 +++ b/distribution/config/bundles.properties Fri Aug 31 11:26:14 2012 +0200 @@ -20,7 +20,10 @@ thermostat-thread-client-swing-@project.version@.jar, \ thermostat-thread-client-controllers-@project.version@.jar, \ thermostat-thread-client-common-@project.version@.jar, \ - thermostat-osgi-process-handler-@project.version@.jar + thermostat-osgi-process-handler-@project.version@.jar, \ + thermostat-client-command-@project.version@.jar, \ + thermostat-client-command-@project.version@.jar, \ + thermostat-agent-command-@project.version@.jar service = thermostat-agent-core-@project.version@.jar, \ thermostat-osgi-process-handler-@project.version@.jar, \ @@ -36,6 +39,9 @@ thermostat-common-command-@project.version@.jar, \ thermostat-agent-command-@project.version@.jar, \ thermostat-agent-heapdumper-@project.version@.jar + thermostat-thread-collector-@project.version@.jar, \ + thermostat-thread-harvester-@project.version@.jar, \ + thermostat-client-command-@project.version@.jar storage = thermostat-agent-core-@project.version@.jar, \ thermostat-osgi-process-handler-@project.version@.jar, \
--- a/distribution/pom.xml Fri Aug 31 11:22:52 2012 +0200 +++ b/distribution/pom.xml Fri Aug 31 11:26:14 2012 +0200 @@ -352,6 +352,11 @@ <artifactId>thermostat-thread-collector</artifactId> <version>${project.version}</version> </dependency> - + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-thread-harvester</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> </project>
--- a/thread/client-common/pom.xml Fri Aug 31 11:22:52 2012 +0200 +++ b/thread/client-common/pom.xml Fri Aug 31 11:26:14 2012 +0200 @@ -102,11 +102,17 @@ <instructions> <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor> <Bundle-SymbolicName>com.redhat.thermostat.thread.client.common</Bundle-SymbolicName> + <Bundle-Activator>com.redhat.thermostat.thread.client.common.osgi.Activator</Bundle-Activator> <Export-Package> com.redhat.thermostat.thread.client.common, com.redhat.thermostat.thread.client.common.locale, com.redhat.thermostat.thread.client.common.chart, + 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.osgi, + </Private-Package> <!-- Do not autogenerate uses clauses in Manifests --> <_nouses>true</_nouses> </instructions>
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadView.java Fri Aug 31 11:22:52 2012 +0200 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/ThreadView.java Fri Aug 31 11:26:14 2012 +0200 @@ -62,7 +62,7 @@ notifier.removeActionListener(listener); } - public abstract void setRecording(boolean recording); + public abstract void setRecording(boolean recording, boolean notify); public abstract void setDaemonThreads(String daemonThreads); public abstract void setLiveThreads(String liveThreads); @@ -70,4 +70,6 @@ public abstract VMThreadCapabilitiesView createVMThreadCapabilitiesView(); public abstract ThreadTableView createThreadTableView(); + + public abstract void displayWarning(String warning); }
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/VMThreadCapabilitiesView.java Fri Aug 31 11:22:52 2012 +0200 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/VMThreadCapabilitiesView.java Fri Aug 31 11:26:14 2012 +0200 @@ -37,7 +37,7 @@ package com.redhat.thermostat.thread.client.common; import com.redhat.thermostat.client.osgi.service.BasicView; -import com.redhat.thermostat.thread.collector.VMThreadCapabilities; +import com.redhat.thermostat.thread.model.VMThreadCapabilities; public abstract class VMThreadCapabilitiesView extends BasicView {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/ThreadCollector.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,69 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are 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; + +import java.util.List; + +import com.redhat.thermostat.thread.model.ThreadInfoData; +import com.redhat.thermostat.thread.model.ThreadSummary; +import com.redhat.thermostat.thread.model.VMThreadCapabilities; + +public interface ThreadCollector { + + VMThreadCapabilities getVMThreadCapabilities(); + + boolean startHarvester(); + boolean stopHarvester(); + boolean isHarvesterCollecting(); + + ThreadSummary getLatestThreadSummary(); + List<ThreadSummary> getThreadSummary(long since); + List<ThreadSummary> getThreadSummary(); + + /** + * Return a list of {@link ThreadInfoData}, sorted in descending order their by + * {@link ThreadInfoData#getTimeStamp()}, whose elements are at most + * "{@code since}" old. + */ + List<ThreadInfoData> getThreadInfo(long since); + + /** + * Return a list of all the {@link ThreadInfoData} collected, sorted in + * descending order their by {@link ThreadInfoData#getTimeStamp()}. + */ + List<ThreadInfoData> getThreadInfo(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/ThreadCollectorFactory.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,44 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are 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; + +import com.redhat.thermostat.common.dao.VmRef; + +public interface ThreadCollectorFactory { + + ThreadCollector getCollector(VmRef reference); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/impl/ThreadCollectorFactoryImpl.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are 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.common.dao.VmRef; +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 ThreadDao threadDao; + + public ThreadCollectorFactoryImpl(ThreadDao threadDao) { + this.threadDao = threadDao; + } + + @Override + public synchronized ThreadCollector getCollector(VmRef reference) { + return new ThreadMXBeanCollector(threadDao, reference); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/collector/impl/ThreadMXBeanCollector.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,248 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are 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 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.Request.RequestType; +import com.redhat.thermostat.common.dao.HostRef; +import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.common.utils.OSGIUtils; +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.ThreadInfoData; +import com.redhat.thermostat.thread.model.ThreadSummary; +import com.redhat.thermostat.thread.model.VMThreadCapabilities; + +public class ThreadMXBeanCollector implements ThreadCollector { + + private ThreadDao threadDao; + private VmRef ref; + + public ThreadMXBeanCollector(ThreadDao threadDao, VmRef ref) { + this.threadDao = threadDao; + this.ref = ref; + } + + Request createRequest() { + HostRef targetHostRef = ref.getAgent(); + + // todo + String address = threadDao.getStorage().getConfigListenAddress(targetHostRef); + String [] host = address.split(":"); + + InetSocketAddress target = new InetSocketAddress(host[0], Integer.parseInt(host[1])); + Request harvester = new Request(RequestType.RESPONSE_EXPECTED, target); + + harvester.setReceiver(HarvesterCommand.RECEIVER); + + return harvester; + } + + @Override + public boolean startHarvester() { + + Request harvester = createRequest(); + harvester.setParameter(HarvesterCommand.class.getName(), HarvesterCommand.START.name()); + harvester.setParameter(HarvesterCommand.VM_ID.name(), ref.getIdString()); + harvester.setParameter(HarvesterCommand.AGENT_ID.name(), ref.getAgent().getAgentId()); + + 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(); + } + }); + + RequestQueue queue = getRequestQueue(); + queue.putRequest(harvester); + + try { + latch.await(); + } catch (InterruptedException ignore) {} + + return result[0]; + } + + @Override + public boolean stopHarvester() { + + Request harvester = createRequest(); + harvester.setParameter(HarvesterCommand.class.getName(), HarvesterCommand.STOP.name()); + harvester.setParameter(HarvesterCommand.VM_ID.name(), ref.getIdString()); + + 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(); + } + }); + + RequestQueue queue = getRequestQueue(); + queue.putRequest(harvester); + + try { + latch.await(); + } catch (InterruptedException ignore) {} + return result[0]; + } + + @Override + public boolean isHarvesterCollecting() { + Request harvester = createRequest(); + harvester.setParameter(HarvesterCommand.class.getName(), HarvesterCommand.IS_COLLECTING.name()); + harvester.setParameter(HarvesterCommand.VM_ID.name(), ref.getIdString()); + + 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(); + } + }); + + RequestQueue queue = getRequestQueue(); + queue.putRequest(harvester); + + try { + latch.await(); + } catch (InterruptedException ignore) {} + return result[0]; + } + + @Override + public ThreadSummary getLatestThreadSummary() { + ThreadSummary summary = threadDao.loadLastestSummary(ref); + if (summary == null) { + // default to all 0 + summary = new ThreadSummary(); + } + return summary; + } + + @Override + public List<ThreadSummary> getThreadSummary(long since) { + List<ThreadSummary> summary = threadDao.loadSummary(ref, since); + return summary; + } + + @Override + public List<ThreadSummary> getThreadSummary() { + return getThreadSummary(0); + } + + @Override + public List<ThreadInfoData> getThreadInfo() { + return getThreadInfo(0); + } + + @Override + public List<ThreadInfoData> getThreadInfo(long since) { + return threadDao.loadThreadInfo(ref, since); + } + + @Override + public VMThreadCapabilities getVMThreadCapabilities() { + + VMThreadCapabilities caps = threadDao.loadCapabilities(ref); + if (caps == null) { + Request harvester = createRequest(); + harvester.setParameter(HarvesterCommand.class.getName(), HarvesterCommand.VM_CAPS.name()); + harvester.setParameter(HarvesterCommand.VM_ID.name(), ref.getIdString()); + harvester.setParameter(HarvesterCommand.AGENT_ID.name(), ref.getAgent().getAgentId()); + + final CountDownLatch latch = new CountDownLatch(1); + harvester.addListener(new RequestResponseListener() { + @Override + public void fireComplete(Request request, Response response) { + latch.countDown(); + } + }); + + RequestQueue queue = getRequestQueue(); + queue.putRequest(harvester); + + try { + latch.await(); + caps = threadDao.loadCapabilities(ref); + } catch (InterruptedException ignore) { + caps = new VMThreadCapabilities(); + } + } + return caps; + } + + RequestQueue getRequestQueue() { + return OSGIUtils.getInstance().getService(RequestQueue.class); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/osgi/Activator.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,77 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are 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.osgi; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTracker; + +import com.redhat.thermostat.common.storage.Storage; +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; +import com.redhat.thermostat.thread.dao.impl.ThreadDaoImpl; + +public class Activator implements BundleActivator { + + private ThreadCollectorFactoryImpl collectorFactory; + + @Override + public void start(final BundleContext context) throws Exception { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + ServiceTracker tracker = new ServiceTracker(context, ThreadDao.class.getName(), null) { + @Override + public Object addingService(ServiceReference reference) { + + ThreadDao threadDao = (ThreadDao) context.getService(reference); + + collectorFactory = new ThreadCollectorFactoryImpl(threadDao); + + context.registerService(ThreadCollectorFactory.class.getName(), collectorFactory, null); + + return super.addingService(reference); + } + }; + tracker.open(); + } + + @Override + public void stop(BundleContext context) throws Exception { + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/client-common/src/test/java/com/redhat/thermostat/thread/client/common/collector/ThreadCollectorFactoryTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are 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; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; + +import java.util.concurrent.ScheduledExecutorService; + +import org.junit.Test; + +import com.redhat.thermostat.common.dao.VmRef; +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 ThreadCollectorFactoryTest { + + @Test + public void testThreadCollectorFactory() { + ThreadDao threadDao = mock(ThreadDao.class); + VmRef reference = mock(VmRef.class); + + ThreadCollectorFactory factory = new ThreadCollectorFactoryImpl(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/impl/ThreadCollectorTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,256 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are 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.assertSame; +import static org.junit.Assert.fail; + +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 static org.mockito.Mockito.times; + +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.common.dao.HostRef; +import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.client.common.collector.impl.ThreadMXBeanCollector; +import com.redhat.thermostat.thread.collector.HarvesterCommand; +import com.redhat.thermostat.thread.dao.ThreadDao; +import com.redhat.thermostat.thread.model.VMThreadCapabilities; + +public class ThreadCollectorTest { + + @Test + public void testVMCapabilitiesNotInDAO() throws Exception { + + HostRef agent = mock(HostRef.class); + when(agent.getAgentId()).thenReturn("42"); + + VmRef reference = mock(VmRef.class); + when(reference.getIdString()).thenReturn("00101010"); + when(reference.getAgent()).thenReturn(agent); + ThreadDao threadDao = mock(ThreadDao.class); + + VMThreadCapabilities resCaps = mock(VMThreadCapabilities.class); + when(threadDao.loadCapabilities(reference)).thenReturn(null).thenReturn(resCaps); + + final Request request = mock(Request.class); + final RequestQueue requestQueue = mock(RequestQueue.class); + + 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(null, null); + + return null; + } + + }).when(requestQueue).putRequest(request); + + /* ************* */ + + ThreadCollector collector = new ThreadMXBeanCollector(threadDao, reference) { + @Override + Request createRequest() { + return request; + } + @Override + RequestQueue getRequestQueue() { + return requestQueue; + } + }; + + VMThreadCapabilities caps = collector.getVMThreadCapabilities(); + + verify(request).setParameter(HarvesterCommand.class.getName(), HarvesterCommand.VM_CAPS.name()); + verify(request).setParameter(HarvesterCommand.VM_ID.name(), "00101010"); + verify(request).setParameter(HarvesterCommand.AGENT_ID.name(), "42"); + + verify(requestQueue).putRequest(request); + + verify(threadDao, times(2)).loadCapabilities(reference); + assertSame(resCaps, caps); + } + + @Test + public void testVMCapabilitiesInDAO() throws Exception { + + VmRef reference = mock(VmRef.class); + ThreadDao threadDao = mock(ThreadDao.class); + + VMThreadCapabilities resCaps = mock(VMThreadCapabilities.class); + when(threadDao.loadCapabilities(reference)).thenReturn(resCaps); + + ThreadCollector collector = new ThreadMXBeanCollector(threadDao, reference) { + @Override + Request createRequest() { + fail(); + return null; + } + @Override + RequestQueue getRequestQueue() { + fail(); + return null; + } + }; + + VMThreadCapabilities caps = collector.getVMThreadCapabilities(); + + verify(threadDao, times(1)).loadCapabilities(reference); + assertSame(resCaps, caps); + } + + @Test + public void testStart() { + + HostRef agent = mock(HostRef.class); + when(agent.getAgentId()).thenReturn("42"); + + final Request request = mock(Request.class); + final RequestQueue requestQueue = mock(RequestQueue.class); + ThreadDao threadDao = mock(ThreadDao.class); + VmRef reference = mock(VmRef.class); + when(reference.getIdString()).thenReturn("00101010"); + when(reference.getAgent()).thenReturn(agent); + + 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(threadDao, reference) { + @Override + Request createRequest() { + return request; + } + @Override + RequestQueue getRequestQueue() { + return requestQueue; + } + }; + + collector.startHarvester(); + + verify(request).setParameter(HarvesterCommand.class.getName(), HarvesterCommand.START.name()); + verify(request).setParameter(HarvesterCommand.VM_ID.name(), "00101010"); + verify(request).setParameter(HarvesterCommand.AGENT_ID.name(), "42"); + + verify(requestQueue).putRequest(request); + } + + + @Test + public void testStop() { + + final Request request = mock(Request.class); + final RequestQueue requestQueue = mock(RequestQueue.class); + ThreadDao threadDao = mock(ThreadDao.class); + VmRef reference = mock(VmRef.class); + when(reference.getIdString()).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()); + + 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(threadDao, reference) { + @Override + Request createRequest() { + return request; + } + @Override + RequestQueue getRequestQueue() { + return requestQueue; + } + }; + collector.stopHarvester(); + + verify(request).setParameter(HarvesterCommand.class.getName(), HarvesterCommand.STOP.name()); + verify(request).setParameter(HarvesterCommand.VM_ID.name(), "00101010"); + + verify(requestQueue).putRequest(request); + } +}
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationController.java Fri Aug 31 11:22:52 2012 +0200 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationController.java Fri Aug 31 11:26:14 2012 +0200 @@ -58,11 +58,11 @@ import com.redhat.thermostat.thread.client.common.VMThreadCapabilitiesView; import com.redhat.thermostat.thread.client.common.ThreadView.ThreadAction; 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.collector.ThreadCollectorFactory; -import com.redhat.thermostat.thread.collector.ThreadCollector; -import com.redhat.thermostat.thread.collector.ThreadCollectorFactory; -import com.redhat.thermostat.thread.collector.ThreadSummary; -import com.redhat.thermostat.thread.collector.VMThreadCapabilities; +import com.redhat.thermostat.thread.model.ThreadSummary; +import com.redhat.thermostat.thread.model.VMThreadCapabilities; public class ThreadInformationController implements VmInformationServiceController { @@ -75,16 +75,12 @@ private Timer timer; private ApplicationCache cache; - String CACHE_RECORDING_KEY = "thread-live-recording-"; - private LivingDaemonThreadDifferenceChart model; - + public ThreadInformationController(VmRef ref, ApplicationService appService, ThreadCollectorFactory collectorFactory, ThreadViewProvider viewFactory) - { - CACHE_RECORDING_KEY = CACHE_RECORDING_KEY + ref.getStringID(); - + { this.appService = appService; cache = appService.getApplicationCache(); @@ -115,7 +111,7 @@ timer.stop(); break; - case VISIBLE: + case VISIBLE: timer.start(); break; @@ -125,17 +121,13 @@ } }); - view.setRecording(isRecording()); + view.setRecording(isRecording(), false); view.addThreadActionListener(new ThreadActionListener()); } private boolean isRecording() { - Boolean isRecording = (Boolean) cache.getAttribute(CACHE_RECORDING_KEY); - return (isRecording != null && isRecording); - } - - private void setRecording(boolean recording) { - cache.addAttribute(CACHE_RECORDING_KEY, recording); + + return collector.isHarvesterCollecting(); } @Override @@ -174,15 +166,24 @@ @Override public void actionPerformed(ActionEvent<ThreadAction> actionEvent) { + + boolean result = false; + switch (actionEvent.getActionId()) { case START_LIVE_RECORDING: - collector.startHarvester(); - setRecording(true); + result = collector.startHarvester(); + if (!result) { + view.displayWarning("Cannot enable Thread recording"); + view.setRecording(false, false); + } break; case STOP_LIVE_RECORDING: - collector.stopHarvester(); - setRecording(false); + result = collector.stopHarvester(); + if (!result) { + view.displayWarning("Cannot disable Thread recording"); + view.setRecording(true, false); + } break; default:
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationService.java Fri Aug 31 11:22:52 2012 +0200 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationService.java Fri Aug 31 11:26:14 2012 +0200 @@ -43,7 +43,7 @@ import com.redhat.thermostat.client.osgi.service.VmInformationServiceController; import com.redhat.thermostat.common.dao.VmRef; import com.redhat.thermostat.thread.client.common.ThreadViewProvider; -import com.redhat.thermostat.thread.collector.ThreadCollectorFactory; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory; public class ThreadInformationService implements VmInformationService {
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTableController.java Fri Aug 31 11:22:52 2012 +0200 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTableController.java Fri Aug 31 11:26:14 2012 +0200 @@ -50,8 +50,8 @@ import com.redhat.thermostat.common.Timer.SchedulingType; import com.redhat.thermostat.thread.client.common.ThreadTableBean; import com.redhat.thermostat.thread.client.common.ThreadTableView; -import com.redhat.thermostat.thread.collector.ThreadCollector; -import com.redhat.thermostat.thread.collector.ThreadInfo; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.model.ThreadInfoData; public class ThreadTableController implements CommonController { @@ -99,7 +99,7 @@ private class ThreadTableControllerAction implements Runnable { @Override public void run() { - List<ThreadInfo> infos = collector.getThreadInfo(); + List<ThreadInfoData> infos = collector.getThreadInfo(); if(infos.size() > 0) { long lastPollTimestamp = infos.get(0).getTimeStamp(); @@ -110,11 +110,11 @@ // first, get a map of all threads with the respective info // the list will contain an ordered-by-timestamp list // with the known history for each thread - Map<ThreadInfo, List<ThreadInfo>> stats = new HashMap<>(); - for (ThreadInfo info : infos) { - List<ThreadInfo> beanList = stats.get(info); + Map<ThreadInfoData, List<ThreadInfoData>> stats = new HashMap<>(); + for (ThreadInfoData info : infos) { + List<ThreadInfoData> beanList = stats.get(info); if (beanList == null) { - beanList = new ArrayList<ThreadInfo>(); + beanList = new ArrayList<ThreadInfoData>(); stats.put(info, beanList); } beanList.add(info); @@ -123,7 +123,7 @@ List<ThreadTableBean> tableBeans = new ArrayList<>(); // now we have the list, we can do all the analysis we need - for (ThreadInfo key : stats.keySet()) { + for (ThreadInfoData key : stats.keySet()) { ThreadTableBean bean = new ThreadTableBean(); bean.setName(key.getName()); @@ -133,7 +133,7 @@ bean.setBlockedCount(key.getBlockedCount()); // get start time and stop time, if any - List<ThreadInfo> beanList = stats.get(key); + List<ThreadInfoData> beanList = stats.get(key); long last = beanList.get(0).getTimeStamp(); long first = beanList.get(beanList.size() - 1).getTimeStamp(); @@ -146,7 +146,7 @@ // time for some stats double running = 0; double waiting = 0; - for (ThreadInfo info : beanList) { + for (ThreadInfoData info : beanList) { State state = info.getState(); switch (state) { case RUNNABLE:
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/VMThreadCapabilitiesController.java Fri Aug 31 11:22:52 2012 +0200 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/impl/VMThreadCapabilitiesController.java Fri Aug 31 11:26:14 2012 +0200 @@ -40,8 +40,8 @@ import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.thread.client.common.VMThreadCapabilitiesView; -import com.redhat.thermostat.thread.collector.ThreadCollector; -import com.redhat.thermostat.thread.collector.VMThreadCapabilities; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.model.VMThreadCapabilities; public class VMThreadCapabilitiesController implements CommonController { @@ -61,7 +61,9 @@ switch (actionEvent.getActionId()) { case VISIBLE: VMThreadCapabilities caps = collector.getVMThreadCapabilities(); - view.setVMThreadCapabilities(caps); + if (caps != null) { + view.setVMThreadCapabilities(caps); + } break; default:
--- a/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/osgi/Activator.java Fri Aug 31 11:22:52 2012 +0200 +++ b/thread/client-controllers/src/main/java/com/redhat/thermostat/thread/client/controller/osgi/Activator.java Fri Aug 31 11:26:14 2012 +0200 @@ -46,8 +46,8 @@ import com.redhat.thermostat.common.MultipleServiceTracker; import com.redhat.thermostat.common.MultipleServiceTracker.Action; import com.redhat.thermostat.thread.client.common.ThreadViewProvider; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory; import com.redhat.thermostat.thread.client.controller.impl.ThreadInformationService; -import com.redhat.thermostat.thread.collector.ThreadCollectorFactory; public class Activator implements BundleActivator {
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationControllerTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadInformationControllerTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -42,6 +42,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.times; import org.junit.After; import org.junit.Before; @@ -61,8 +62,8 @@ import com.redhat.thermostat.thread.client.common.ThreadView; import com.redhat.thermostat.thread.client.common.ThreadViewProvider; import com.redhat.thermostat.thread.client.common.VMThreadCapabilitiesView; -import com.redhat.thermostat.thread.collector.ThreadCollector; -import com.redhat.thermostat.thread.collector.ThreadCollectorFactory; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollectorFactory; public class ThreadInformationControllerTest { @@ -74,7 +75,7 @@ private ThreadInformationController controller; private ApplicationService appService; - + @Before public void setUp() { ApplicationContextUtil.resetApplicationContext(); @@ -125,13 +126,15 @@ VmRef ref = mock(VmRef.class); - ThreadCollectorFactory collectorFactory = mock(ThreadCollectorFactory.class); + ThreadCollectorFactory collectorFactory = mock(ThreadCollectorFactory.class); + ThreadCollector collector = mock(ThreadCollector.class); + when(collectorFactory.getCollector(ref)).thenReturn(collector); controller = new ThreadInformationController(ref, appService, collectorFactory, viewFactory); } @Test - public void liveRecodingKeySet() { + public void verifyLiveRecording() { ActionListener<ThreadView.ThreadAction> threadActionListener; ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class); @@ -139,35 +142,39 @@ VmRef ref = mock(VmRef.class); when(ref.getStringID()).thenReturn("42"); + + 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); - - ThreadCollector collector = mock(ThreadCollector.class); when(collectorFactory.getCollector(ref)).thenReturn(collector); ApplicationCache cache = mock(ApplicationCache.class); appService = mock(ApplicationService.class); when(appService.getApplicationCache()).thenReturn(cache); - when(cache.getAttribute(anyString())).thenReturn(false).thenReturn(true); controller = new ThreadInformationController(ref, appService, collectorFactory, viewFactory); - assertEquals("thread-live-recording-42", controller.CACHE_RECORDING_KEY); - verify(cache).getAttribute("thread-live-recording-42"); - verify(view).setRecording(false); + verify(collector).isHarvesterCollecting(); + verify(view, times(1)).setRecording(false, false); threadActionListener = viewArgumentCaptor.getValue(); threadActionListener.actionPerformed(new ActionEvent<>(view, ThreadView.ThreadAction.START_LIVE_RECORDING)); - verify(cache).addAttribute("thread-live-recording-42", true); + verify(view, times(1)).setRecording(false, false); verify(collector).startHarvester(); threadActionListener.actionPerformed(new ActionEvent<>(view, ThreadView.ThreadAction.STOP_LIVE_RECORDING)); - verify(cache).addAttribute("thread-live-recording-42", false); + verify(collector).stopHarvester(); + verify(view, times(1)).setRecording(false, false); - // check that the value indeed persist across sessions - controller = new ThreadInformationController(ref, appService, collectorFactory, viewFactory); - verify(view).setRecording(true); + threadActionListener.actionPerformed(new ActionEvent<>(view, ThreadView.ThreadAction.STOP_LIVE_RECORDING)); + + verify(collector, times(2)).stopHarvester(); + verify(view, times(1)).setRecording(true, false); } @Test
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTableControllerTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/ThreadTableControllerTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -54,8 +54,8 @@ import com.redhat.thermostat.common.Timer; import com.redhat.thermostat.common.appctx.ApplicationContextUtil; import com.redhat.thermostat.thread.client.common.ThreadTableView; -import com.redhat.thermostat.thread.collector.ThreadCollector; -import com.redhat.thermostat.thread.collector.ThreadInfo; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.model.ThreadInfoData; public class ThreadTableControllerTest {
--- a/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/VMThreadCapabilitiesControllerTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/thread/client-controllers/src/test/java/com/redhat/thermostat/thread/client/controller/impl/VMThreadCapabilitiesControllerTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -50,8 +50,8 @@ import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.appctx.ApplicationContextUtil; import com.redhat.thermostat.thread.client.common.VMThreadCapabilitiesView; -import com.redhat.thermostat.thread.collector.ThreadCollector; -import com.redhat.thermostat.thread.collector.VMThreadCapabilities; +import com.redhat.thermostat.thread.client.common.collector.ThreadCollector; +import com.redhat.thermostat.thread.model.VMThreadCapabilities; public class VMThreadCapabilitiesControllerTest {
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadView.java Fri Aug 31 11:22:52 2012 +0200 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadView.java Fri Aug 31 11:26:14 2012 +0200 @@ -40,6 +40,7 @@ import java.awt.event.ItemEvent; import java.awt.event.ItemListener; +import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTabbedPane; import javax.swing.SwingUtilities; @@ -65,6 +66,8 @@ private static final Translate t = LocaleResources.createLocalizer(); + private boolean skipNotification = false; + public SwingThreadView() { panel = new ThreadMainPanel(); @@ -92,6 +95,9 @@ { @Override public void itemStateChanged(ItemEvent e) { + + if (skipNotification) return; + ThreadAction action = null; if (e.getStateChange() == ItemEvent.SELECTED) { action = ThreadAction.START_LIVE_RECORDING; @@ -130,11 +136,13 @@ } @Override - public void setRecording(final boolean recording) { + public void setRecording(final boolean recording, final boolean notify) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { + if (!notify) skipNotification = true; timelinePanel.getRecordButton().setSelected(recording); + if (!notify) skipNotification = false; } }); } @@ -149,8 +157,13 @@ }); } - public void setLiveThreads(String liveThreads) { - timelinePanel.getLiveThreads().setText(liveThreads); + public void setLiveThreads(final String liveThreads) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + timelinePanel.getLiveThreads().setText(liveThreads); + } + }); }; @Override @@ -179,4 +192,14 @@ public ThreadTableView createThreadTableView() { return threadTable; } + + @Override + public void displayWarning(final String warning) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + JOptionPane.showMessageDialog(panel.getParent(), warning, "", JOptionPane.WARNING_MESSAGE); + } + }); + } }
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingVMThreadCapabilitiesView.java Fri Aug 31 11:22:52 2012 +0200 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingVMThreadCapabilitiesView.java Fri Aug 31 11:26:14 2012 +0200 @@ -44,7 +44,7 @@ import com.redhat.thermostat.client.ui.ComponentVisibleListener; import com.redhat.thermostat.client.ui.SwingComponent; import com.redhat.thermostat.thread.client.common.VMThreadCapabilitiesView; -import com.redhat.thermostat.thread.collector.VMThreadCapabilities; +import com.redhat.thermostat.thread.model.VMThreadCapabilities; public class SwingVMThreadCapabilitiesView extends VMThreadCapabilitiesView implements SwingComponent {
--- a/thread/collector/pom.xml Fri Aug 31 11:22:52 2012 +0200 +++ b/thread/collector/pom.xml Fri Aug 31 11:26:14 2012 +0200 @@ -66,6 +66,16 @@ <artifactId>thermostat-common-core</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-agent-command</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-client-command</artifactId> + <version>${project.version}</version> + </dependency> <dependency> <groupId>org.osgi</groupId> @@ -95,17 +105,16 @@ <configuration> <instructions> <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor> - <Bundle-Activator>com.redhat.thermostat.thread.collector.osgi.Activator</Bundle-Activator> + <Bundle-Activator>com.redhat.thermostat.thread.common.osgi.Activator</Bundle-Activator> <Bundle-SymbolicName>com.redhat.thermostat.thread.collector</Bundle-SymbolicName> <Export-Package> com.redhat.thermostat.thread.collector, com.redhat.thermostat.thread.dao, + com.redhat.thermostat.thread.model, </Export-Package> <Private-Package> - com.redhat.thermostat.thread.collector.osgi, - com.redhat.thermostat.thread.collector.impl, + com.redhat.thermostat.thread.common.osgi, com.redhat.thermostat.thread.dao.impl, - com.redhat.thermostat.utils.management, </Private-Package> <!-- Do not autogenerate uses clauses in Manifests --> <_nouses>true</_nouses>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/collector/HarvesterCommand.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,15 @@ +package com.redhat.thermostat.thread.collector; + +public enum HarvesterCommand { + + START, + STOP, + VM_CAPS, + IS_COLLECTING, + + AGENT_ID, + VM_ID; + + public static final String RECEIVER = "com.redhat.thermostat.thread.harvester.ThreadHarvester"; + +}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/collector/ThreadCollector.java Fri Aug 31 11:22:52 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are 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.collector; - -import java.util.List; - -public interface ThreadCollector { - - VMThreadCapabilities getVMThreadCapabilities(); - - void startHarvester(); - void stopHarvester(); - - ThreadSummary getLatestThreadSummary(); - List<ThreadSummary> getThreadSummary(long since); - List<ThreadSummary> getThreadSummary(); - - /** - * Return a list of {@link ThreadInfo}, sorted in descending order their by - * {@link ThreadInfo#getTimeStamp()}, whose elements are at most - * "{@code since}" old. - */ - List<ThreadInfo> getThreadInfo(long since); - - /** - * Return a list of all the {@link ThreadInfo} collected, sorted in - * descending order their by {@link ThreadInfo#getTimeStamp()}. - */ - List<ThreadInfo> getThreadInfo(); -}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/collector/ThreadCollectorFactory.java Fri Aug 31 11:22:52 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are 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.collector; - -import com.redhat.thermostat.common.dao.VmRef; - -public interface ThreadCollectorFactory { - - ThreadCollector getCollector(VmRef reference); -}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/collector/ThreadInfo.java Fri Aug 31 11:22:52 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are 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.collector; - -import java.lang.Thread.State; - -import com.redhat.thermostat.common.model.TimeStampedPojo; - -public interface ThreadInfo extends TimeStampedPojo { - - StackTraceElement[] getStackTrace(); - - String getName(); - - long getAllocatedBytes(); - - long getThreadID(); - - State getState(); - - long getBlockedCount(); - - long getWaitedCount(); - - long getCpuTime(); - - long getUserTime(); -}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/collector/ThreadSummary.java Fri Aug 31 11:22:52 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are 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.collector; - -import com.redhat.thermostat.common.model.TimeStampedPojo; - -public interface ThreadSummary extends TimeStampedPojo { - - /** - * Represents the number of living {@link Thread}s, including daemon - * {@link Thread}s, currently running. - * - * <br /><br /> - * - * A {@link Thread} is alive if it has been created, started and is not - * dead. - * - * @see Thread#isAlive() - * @see Thread.State - */ - long currentLiveThreads(); - - /** - * Represents the number of living {@link Thread}s which are also daemon - * {@link Thread}s, currently running. - * - * <br /><br /> - * - * A {@link Thread} is alive if it has been created, started and is not - * dead. - * - * @see #currentLiveThreads() - * @see Thread#isAlive() - * @see Thread.State - */ - long currentDaemonThreads(); -}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/collector/VMThreadCapabilities.java Fri Aug 31 11:22:52 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are 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.collector; - -import java.util.List; - -public interface VMThreadCapabilities { - - boolean supportCPUTime(); - boolean supportContentionMonitor(); - boolean supportThreadAllocatedMemory(); - - List<String> getSupportedFeaturesList(); -}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/collector/impl/ThreadCollectorFactoryImpl.java Fri Aug 31 11:22:52 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are 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.collector.impl; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ScheduledExecutorService; - -import com.redhat.thermostat.common.dao.VmRef; -import com.redhat.thermostat.thread.collector.ThreadCollector; -import com.redhat.thermostat.thread.collector.ThreadCollectorFactory; -import com.redhat.thermostat.thread.dao.ThreadDao; -import com.redhat.thermostat.utils.management.MXBeanConnector; - -public class ThreadCollectorFactoryImpl implements ThreadCollectorFactory { - - private Map<VmRef, ThreadMXBeanCollector> collectors; - - private ThreadDao threadDao; - private ScheduledExecutorService threadPool; - - public ThreadCollectorFactoryImpl(ThreadDao threadDao, ScheduledExecutorService threadPool) { - this.threadDao = threadDao; - this.threadPool = threadPool; - - collectors = new HashMap<VmRef, ThreadMXBeanCollector>(); - } - - @Override - public synchronized ThreadCollector getCollector(VmRef reference) { - ThreadMXBeanCollector collector = collectors.get(reference); - if (collector == null) { - collector = new ThreadMXBeanCollector(threadDao, reference, new MXBeanConnector(reference), threadPool); - collectors.put(reference, collector); - } - return collector; - } - - public void shutdown() { - for (ThreadMXBeanCollector collector : collectors.values()) { - collector.stopHarvester(); - } - } -}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/collector/impl/ThreadMXBeanCollector.java Fri Aug 31 11:22:52 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,286 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are 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.collector.impl; - -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.lang.management.ThreadInfo; -import java.lang.management.ThreadMXBean; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -import javax.management.MalformedObjectNameException; - -import com.redhat.thermostat.common.dao.VmRef; -import com.redhat.thermostat.thread.collector.ThreadCollector; -import com.redhat.thermostat.thread.collector.ThreadSummary; -import com.redhat.thermostat.thread.collector.VMThreadCapabilities; -import com.redhat.thermostat.thread.dao.ThreadDao; -import com.redhat.thermostat.utils.management.MXBeanConnection; -import com.redhat.thermostat.utils.management.MXBeanConnector; - -@SuppressWarnings("restriction") -public class ThreadMXBeanCollector implements ThreadCollector { - - private ThreadDao threadDao; - private VmRef ref; - private MXBeanConnector connector; - - private MXBeanConnection connection; - private ThreadMXBean collectorBean; - - private boolean isConnected; - private ScheduledExecutorService threadPool; - - private ScheduledFuture<?> harvester; - - public ThreadMXBeanCollector(ThreadDao threadDao, VmRef ref, MXBeanConnector connector, ScheduledExecutorService threadPool) { - this.threadDao = threadDao; - this.ref = ref; - this.connector = connector; - this.threadPool = threadPool; - } - - @Override - public synchronized void startHarvester() { - if (isConnected) return; - - if (!connector.isAttached()) { - try { - connector.attach(); - } catch (Exception ignore) { - ignore.printStackTrace(); - } - } - - try { - connection = connector.connect(); - } catch (Exception e) { - e.printStackTrace(); - } - isConnected = true; - - harvester = threadPool.scheduleAtFixedRate(new Harvester(), 0, 1, TimeUnit.SECONDS); - } - - private class Harvester implements Runnable { - @Override - public void run() { - harvestData(); - } - } - - @Override - public synchronized void stopHarvester() { - if (!isConnected) return; - - harvester.cancel(false); - - try { - connection.close(); - } catch (IOException e) { - e.printStackTrace(); - } - - if (connector.isAttached()) { - try { - connector.close(); - } catch (Exception ignore) { - ignore.printStackTrace(); - } - } - - isConnected = false; - } - - @Override - public ThreadSummary getLatestThreadSummary() { - ThreadSummary summary = threadDao.loadLastestSummary(ref); - if (summary == null) { - // default to all 0 - summary = new ThreadMXSummary(); - } - return summary; - } - - @Override - public List<ThreadSummary> getThreadSummary(long since) { - List<ThreadSummary> summary = threadDao.loadSummary(ref, since); - return summary; - } - - @Override - public List<ThreadSummary> getThreadSummary() { - return getThreadSummary(0); - } - - @Override - public List<com.redhat.thermostat.thread.collector.ThreadInfo> getThreadInfo() { - return getThreadInfo(0); - } - - @Override - public List<com.redhat.thermostat.thread.collector.ThreadInfo> getThreadInfo(long since) { - return threadDao.loadThreadInfo(ref, since); - } - - public synchronized void harvestData() { - try { - - long timestamp = System.currentTimeMillis(); - - ThreadMXSummary summary = new ThreadMXSummary(); - - collectorBean = getDataCollectorBean(connection); - - summary.setCurrentLiveThreads(collectorBean.getThreadCount()); - summary.setDaemonThreads(collectorBean.getDaemonThreadCount()); - summary.setTimestamp(timestamp); - - threadDao.saveSummary(ref, summary); - - long [] ids = collectorBean.getAllThreadIds(); - long[] allocatedBytes = null; - - // now the details for the threads - if (collectorBean instanceof com.sun.management.ThreadMXBean) { - com.sun.management.ThreadMXBean sunBean = (com.sun.management.ThreadMXBean) collectorBean; - boolean wasEnabled = false; - if (sunBean.isThreadAllocatedMemorySupported()) { - wasEnabled = sunBean.isThreadAllocatedMemoryEnabled(); - sunBean.setThreadAllocatedMemoryEnabled(true); - allocatedBytes = sunBean.getThreadAllocatedBytes(ids); - sunBean.setThreadAllocatedMemoryEnabled(wasEnabled); - } - } - - ThreadInfo[] threadInfos = collectorBean.getThreadInfo(ids, true, true); - - for (int i = 0; i < ids.length; i++) { - ThreadMXInfo info = new ThreadMXInfo(); - ThreadInfo beanInfo = threadInfos[i]; - - info.setTimeStamp(timestamp); - - info.setName(beanInfo.getThreadName()); - info.setID(beanInfo.getThreadId()); - info.setState(beanInfo.getThreadState()); - info.setStackTrace(beanInfo.getStackTrace()); - - info.setCPUTime(collectorBean.getThreadCpuTime(info.getThreadID())); - info.setUserTime(collectorBean.getThreadUserTime(info.getThreadID())); - - info.setBlockedCount(beanInfo.getBlockedCount()); - info.setWaitedCount(beanInfo.getWaitedCount()); - - if (allocatedBytes != null) { - info.setAllocatedBytes(allocatedBytes[i]); - } - - threadDao.saveThreadInfo(ref, info); - } - - } catch (MalformedObjectNameException e) { - e.printStackTrace(); - } - } - - @Override - public synchronized VMThreadCapabilities getVMThreadCapabilities() { - - VMThreadCapabilities caps = threadDao.loadCapabilities(ref); - if (caps == null) { - if (!connector.isAttached()) { - try { - connector.attach(); - } catch (Exception ignore) { - ignore.printStackTrace(); - } - } - - // query caps to the vm, then save for later - try (MXBeanConnection connection = connector.connect()) { - - ThreadMXBean bean = getDataCollectorBean(connection); - VMThreadMXCapabilities _caps = new VMThreadMXCapabilities(); - - if (bean.isThreadCpuTimeSupported()) _caps.addFeature(ThreadDao.CPU_TIME); - if (bean.isThreadContentionMonitoringSupported()) _caps.addFeature(ThreadDao.CONTENTION_MONITOR); - - if (bean instanceof com.sun.management.ThreadMXBean) { - com.sun.management.ThreadMXBean sunBean = (com.sun.management.ThreadMXBean) bean; - if (sunBean.isThreadAllocatedMemorySupported()) - _caps.addFeature(ThreadDao.THREAD_ALLOCATED_MEMORY); - } - - caps = _caps; - - threadDao.saveCapabilities(ref, caps); - - } catch (Exception e) { - e.printStackTrace(); - } - - if (connector.isAttached()) { - try { - connector.close(); - } catch (Exception ignore) { - ignore.printStackTrace(); - } - } - } - - return caps; - } - - private ThreadMXBean getDataCollectorBean(MXBeanConnection connection) throws MalformedObjectNameException { - ThreadMXBean bean = null; - try { - bean = connection.createProxy(ManagementFactory.THREAD_MXBEAN_NAME, - com.sun.management.ThreadMXBean.class); - } catch (MalformedObjectNameException ignore) {} - - if (bean == null) { - bean = connection.createProxy(ManagementFactory.THREAD_MXBEAN_NAME, - ThreadMXBean.class); - } - return bean; - } -}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/collector/impl/ThreadMXInfo.java Fri Aug 31 11:22:52 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,188 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are 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.collector.impl; - -import java.lang.Thread.State; -import java.util.Arrays; - -import com.redhat.thermostat.thread.collector.ThreadInfo; - -public class ThreadMXInfo implements ThreadInfo { - - private StackTraceElement[] stackTrace; - private long threadID; - private State threadState; - private String name; - private long allocatedBytes; - - private long threadCpuTime; - private long threadUserTime; - private long blockedCount; - private long waitedCount; - - private long timestamp; - - public void setStackTrace(StackTraceElement[] stackTrace) { - this.stackTrace = stackTrace; - } - - @Override - public StackTraceElement[] getStackTrace() { - return stackTrace; - } - - @Override - public String toString() { - return "ThreadMXInfo [name=" + name - + ", threadID=" + threadID + ", threadState=" + threadState - + ", stackTrace=" + Arrays.toString(stackTrace) - + ", allocatedBytes=" + allocatedBytes - + ", threadCpuTime=" + threadCpuTime + ", threadUserTime=" - + threadUserTime + ", blockedCount=" + blockedCount - + ", waitedCount=" + waitedCount + ", timestamp=" + timestamp - + "]"; - } - - public void setName(String threadName) { - this.name = threadName; - } - - public void setID(long threadID) { - this.threadID = threadID; - } - - public void setState(State threadState) { - this.threadState = threadState; - } - - public void setAllocatedBytes(long allocatedBytes) { - this.allocatedBytes = allocatedBytes; - } - - @Override - public String getName() { - return name; - } - - @Override - public long getAllocatedBytes() { - return allocatedBytes; - } - - @Override - public long getThreadID() { - return threadID; - } - - @Override - public State getState() { - return threadState; - } - - @Override - public long getTimeStamp() { - return timestamp; - } - - public void setTimeStamp(long timestamp) { - this.timestamp = timestamp; - } - - public void setCPUTime(long threadCpuTime) { - this.threadCpuTime = threadCpuTime; - } - - public void setUserTime(long threadUserTime) { - this.threadUserTime = threadUserTime; - } - - public void setBlockedCount(long blockedCount) { - this.blockedCount = blockedCount; - } - - public void setWaitedCount(long waitedCount) { - this.waitedCount = waitedCount; - } - - @Override - public long getBlockedCount() { - return blockedCount; - } - - @Override - public long getWaitedCount() { - return waitedCount; - } - - @Override - public long getCpuTime() { - return threadCpuTime; - } - - @Override - public long getUserTime() { - return threadUserTime; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((name == null) ? 0 : name.hashCode()); - result = prime * result + (int) (threadID ^ (threadID >>> 32)); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - ThreadMXInfo other = (ThreadMXInfo) obj; - if (name == null) { - if (other.name != null) - return false; - } else if (!name.equals(other.name)) - return false; - if (threadID != other.threadID) - return false; - return true; - } -}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/collector/impl/ThreadMXSummary.java Fri Aug 31 11:22:52 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are 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.collector.impl; - -import com.redhat.thermostat.thread.collector.ThreadSummary; - -public class ThreadMXSummary implements ThreadSummary { - - private long currentLiveThreads; - private long daemonThreads; - - private long timestamp; - - @Override - public long currentLiveThreads() { - return currentLiveThreads; - } - - public void setCurrentLiveThreads(long currentLiveThreads) { - this.currentLiveThreads = currentLiveThreads; - } - - @Override - public long currentDaemonThreads() { - return daemonThreads; - } - - public void setDaemonThreads(long daemonThreads) { - this.daemonThreads = daemonThreads; - } - - @Override - public long getTimeStamp() { - return timestamp; - } - - public void setTimestamp(long timestamp) { - this.timestamp = timestamp; - } - - @Override - public String toString() { - return "[timestamp: " + timestamp + ", currentLiveThreads: " + - currentLiveThreads + ", daemonThreads: " + daemonThreads + "]"; - } -}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/collector/impl/VMThreadMXCapabilities.java Fri Aug 31 11:22:52 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are 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.collector.impl; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import com.redhat.thermostat.common.storage.Key; -import com.redhat.thermostat.thread.collector.VMThreadCapabilities; -import com.redhat.thermostat.thread.dao.ThreadDao; - -public class VMThreadMXCapabilities implements VMThreadCapabilities { - - private Set<String> features = new HashSet<>(); - - @Override - public boolean supportCPUTime() { - return features.contains(ThreadDao.CPU_TIME); - } - - @Override - public boolean supportContentionMonitor() { - return features.contains(ThreadDao.CONTENTION_MONITOR); - } - - @Override - public String toString() { - return "[supportCPU: " + supportCPUTime() + ", supportContention: " + supportContentionMonitor() + - ", supportThreadAllocatedMemory: " + supportThreadAllocatedMemory() + "]"; - } - - @Override - public boolean supportThreadAllocatedMemory() { - return features.contains(ThreadDao.THREAD_ALLOCATED_MEMORY); - } - - @Override - public List<String> getSupportedFeaturesList() { - return new ArrayList<>(features); - } - - public void addFeature(String feature) { - features.add(feature); - } -}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/collector/osgi/Activator.java Fri Aug 31 11:22:52 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are 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.collector.osgi; - -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; - -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.util.tracker.ServiceTracker; - -import com.redhat.thermostat.common.storage.Storage; -import com.redhat.thermostat.thread.collector.ThreadCollectorFactory; -import com.redhat.thermostat.thread.collector.impl.ThreadCollectorFactoryImpl; -import com.redhat.thermostat.thread.dao.ThreadDao; -import com.redhat.thermostat.thread.dao.impl.ThreadDaoImpl; - -public class Activator implements BundleActivator { - - private ScheduledExecutorService executor = Executors.newScheduledThreadPool(24); - private ThreadCollectorFactoryImpl collectorFactory; - - @Override - public void start(final BundleContext context) throws Exception { - @SuppressWarnings({ "rawtypes", "unchecked" }) - ServiceTracker tracker = new ServiceTracker(context, Storage.class.getName(), null) { - @Override - public Object addingService(ServiceReference reference) { - - Storage storage = (Storage) context.getService(reference); - - ThreadDao threadDao = new ThreadDaoImpl(storage); - collectorFactory = new ThreadCollectorFactoryImpl(threadDao, executor); - - context.registerService(ThreadCollectorFactory.class.getName(), collectorFactory, null); - - return super.addingService(reference); - } - }; - tracker.open(); - } - - @Override - public void stop(BundleContext context) throws Exception { - if (collectorFactory != null) { - collectorFactory.shutdown(); - } - if (executor != null) { - executor.shutdown(); - } - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/common/osgi/Activator.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are 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.common.osgi; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; +import org.osgi.util.tracker.ServiceTracker; + +import com.redhat.thermostat.common.storage.Storage; +import com.redhat.thermostat.thread.dao.ThreadDao; +import com.redhat.thermostat.thread.dao.impl.ThreadDaoImpl; + +public class Activator implements BundleActivator { + + @SuppressWarnings("rawtypes") + private ServiceRegistration reg; + + @Override + public void start(BundleContext context) throws Exception { + + + @SuppressWarnings({ "rawtypes", "unchecked" }) + ServiceTracker tracker = new ServiceTracker(context, Storage.class.getName(), null) { + @Override + public Object addingService(ServiceReference reference) { + Storage storage = (Storage) context.getService(reference); + ThreadDao threadDao = new ThreadDaoImpl(storage); + reg = context.registerService(ThreadDao.class.getName(), threadDao, null); + return super.addingService(reference); + } + }; + tracker.open(); + } + + @Override + public void stop(BundleContext context) throws Exception { + if (reg != null) { + reg.unregister(); + } + } + +}
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/ThreadDao.java Fri Aug 31 11:22:52 2012 +0200 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/ThreadDao.java Fri Aug 31 11:26:14 2012 +0200 @@ -41,9 +41,10 @@ import com.redhat.thermostat.common.dao.VmRef; import com.redhat.thermostat.common.storage.Category; import com.redhat.thermostat.common.storage.Key; -import com.redhat.thermostat.thread.collector.ThreadInfo; -import com.redhat.thermostat.thread.collector.ThreadSummary; -import com.redhat.thermostat.thread.collector.VMThreadCapabilities; +import com.redhat.thermostat.common.storage.Storage; +import com.redhat.thermostat.thread.model.ThreadInfoData; +import com.redhat.thermostat.thread.model.ThreadSummary; +import com.redhat.thermostat.thread.model.VMThreadCapabilities; public interface ThreadDao { @@ -62,7 +63,7 @@ VMThreadCapabilities loadCapabilities(VmRef ref); - void saveCapabilities(VmRef ref, VMThreadCapabilities caps); + void saveCapabilities(String vmId, String agentId, VMThreadCapabilities caps); static final String LIVE_THREADS = "thread-living"; static final Key<Long> LIVE_THREADS_KEY = new Key<Long>(LIVE_THREADS, false); @@ -74,7 +75,7 @@ Key.TIMESTAMP, LIVE_THREADS_KEY, DAEMON_THREADS_KEY); - void saveSummary(VmRef vm, ThreadSummary summary); + void saveSummary(String vmId, String agentId, ThreadSummary summary); ThreadSummary loadLastestSummary(VmRef ref); List<ThreadSummary> loadSummary(VmRef ref, long since); @@ -104,6 +105,8 @@ THREAD_USER_TIME_KEY, THREAD_BLOCKED_COUNT_KEY, THREAD_WAIT_COUNT_KEY, THREAD_STACK_TRACE_ID_KEY); - void saveThreadInfo(VmRef ref, ThreadInfo info); - List<ThreadInfo> loadThreadInfo(VmRef ref, long since); + void saveThreadInfo(String vmId, String agentId, ThreadInfoData info); + List<ThreadInfoData> loadThreadInfo(VmRef ref, long since); + + Storage getStorage(); }
--- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java Fri Aug 31 11:22:52 2012 +0200 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImpl.java Fri Aug 31 11:26:14 2012 +0200 @@ -45,13 +45,10 @@ import com.redhat.thermostat.common.storage.Cursor; import com.redhat.thermostat.common.storage.Key; import com.redhat.thermostat.common.storage.Storage; -import com.redhat.thermostat.thread.collector.ThreadInfo; -import com.redhat.thermostat.thread.collector.ThreadSummary; -import com.redhat.thermostat.thread.collector.VMThreadCapabilities; -import com.redhat.thermostat.thread.collector.impl.ThreadMXInfo; -import com.redhat.thermostat.thread.collector.impl.ThreadMXSummary; -import com.redhat.thermostat.thread.collector.impl.VMThreadMXCapabilities; import com.redhat.thermostat.thread.dao.ThreadDao; +import com.redhat.thermostat.thread.model.ThreadInfoData; +import com.redhat.thermostat.thread.model.ThreadSummary; +import com.redhat.thermostat.thread.model.VMThreadCapabilities; public class ThreadDaoImpl implements ThreadDao { @@ -66,7 +63,7 @@ @Override public VMThreadCapabilities loadCapabilities(VmRef vm) { - VMThreadMXCapabilities caps = null; + VMThreadCapabilities caps = null; Chunk query = new Chunk(THREAD_CAPABILITIES, false); query.put(Key.VM_ID, vm.getId()); @@ -74,7 +71,7 @@ Chunk found = storage.find(query); if (found != null) { - caps = new VMThreadMXCapabilities(); + caps = new VMThreadCapabilities(); if (found.get(CONTENTION_MONITOR_KEY)) caps.addFeature(CONTENTION_MONITOR); if (found.get(CPU_TIME_KEY)) caps.addFeature(CPU_TIME); if (found.get(THREAD_ALLOCATED_MEMORY_KEY)) caps.addFeature(THREAD_ALLOCATED_MEMORY); @@ -84,8 +81,8 @@ } @Override - public void saveCapabilities(VmRef vm, VMThreadCapabilities caps) { - Chunk chunk = prepareChunk(THREAD_CAPABILITIES, true, vm); + public void saveCapabilities(String vmId, String agentId, VMThreadCapabilities caps) { + Chunk chunk = prepareChunk(THREAD_CAPABILITIES, true, vmId, agentId); chunk.put(CONTENTION_MONITOR_KEY, caps.supportContentionMonitor()); chunk.put(CPU_TIME_KEY, caps.supportCPUTime()); @@ -95,8 +92,8 @@ } @Override - public void saveSummary(VmRef vm, ThreadSummary summary) { - Chunk chunk = prepareChunk(THREAD_SUMMARY, false, vm); + public void saveSummary(String vmId, String agentId, ThreadSummary summary) { + Chunk chunk = prepareChunk(THREAD_SUMMARY, false, vmId, agentId); chunk.put(LIVE_THREADS_KEY, summary.currentLiveThreads()); chunk.put(DAEMON_THREADS_KEY, summary.currentDaemonThreads()); @@ -107,13 +104,13 @@ @Override public ThreadSummary loadLastestSummary(VmRef ref) { - ThreadMXSummary summary = null; + ThreadSummary summary = null; Chunk query = prepareChunk(THREAD_SUMMARY, false, ref); Cursor cursor = storage.findAll(query).sort(Key.TIMESTAMP, Cursor.SortDirection.DESCENDING).limit(1); if (cursor.hasNext()) { Chunk found = cursor.next(); - summary = new ThreadMXSummary(); + summary = new ThreadSummary(); summary.setTimestamp(found.get(Key.TIMESTAMP)); summary.setCurrentLiveThreads(found.get(LIVE_THREADS_KEY)); summary.setDaemonThreads(found.get(DAEMON_THREADS_KEY)); @@ -132,7 +129,7 @@ Cursor cursor = storage.findAll(query).sort(Key.TIMESTAMP, Cursor.SortDirection.DESCENDING); while (cursor.hasNext()) { - ThreadMXSummary summary = new ThreadMXSummary(); + ThreadSummary summary = new ThreadSummary(); Chunk found = cursor.next(); summary.setTimestamp(found.get(Key.TIMESTAMP)); @@ -145,8 +142,8 @@ } @Override - public void saveThreadInfo(VmRef ref, ThreadInfo info) { - Chunk chunk = prepareChunk(THREAD_INFO, false, ref); + public void saveThreadInfo(String vmId, String agentId, ThreadInfoData info) { + Chunk chunk = prepareChunk(THREAD_INFO, false, vmId, agentId); chunk.put(Key.TIMESTAMP, info.getTimeStamp()); @@ -163,15 +160,15 @@ } @Override - public List<ThreadInfo> loadThreadInfo(VmRef ref, long since) { - List<ThreadInfo> result = new ArrayList<>(); + public List<ThreadInfoData> loadThreadInfo(VmRef ref, long since) { + List<ThreadInfoData> result = new ArrayList<>(); Chunk query = prepareChunk(THREAD_INFO, false, ref); query.put(Key.WHERE, "this.timestamp > " + since); Cursor cursor = storage.findAll(query).sort(Key.TIMESTAMP, Cursor.SortDirection.DESCENDING); while (cursor.hasNext()) { - ThreadMXInfo info = new ThreadMXInfo(); + ThreadInfoData info = new ThreadInfoData(); Chunk found = cursor.next(); info.setTimeStamp(found.get(Key.TIMESTAMP)); @@ -191,10 +188,19 @@ return result; } - private Chunk prepareChunk(Category category, boolean replace, VmRef vm) { + private Chunk prepareChunk(Category category, boolean replace, String vmId, String agentId) { Chunk chunk = new Chunk(category, replace); - chunk.put(Key.AGENT_ID, vm.getAgent().getAgentId()); - chunk.put(Key.VM_ID, vm.getId()); + chunk.put(Key.AGENT_ID, agentId); + chunk.put(Key.VM_ID, Integer.valueOf(vmId)); return chunk; } + + private Chunk prepareChunk(Category category, boolean replace, VmRef vm) { + return prepareChunk(category, replace, vm.getIdString(), vm.getAgent().getAgentId()); + } + + @Override + public Storage getStorage() { + return storage; + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadInfoData.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,178 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are 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.model; + +import java.lang.Thread.State; +import java.util.Arrays; + +import com.redhat.thermostat.common.model.TimeStampedPojo; + + +public class ThreadInfoData implements TimeStampedPojo { + + private StackTraceElement[] stackTrace; + private long threadID; + private State threadState; + private String name; + private long allocatedBytes; + + private long threadCpuTime; + private long threadUserTime; + private long blockedCount; + private long waitedCount; + + private long timestamp; + + public void setStackTrace(StackTraceElement[] stackTrace) { + this.stackTrace = stackTrace; + } + + public StackTraceElement[] getStackTrace() { + return stackTrace; + } + + @Override + public String toString() { + return "ThreadMXInfo [name=" + name + + ", threadID=" + threadID + ", threadState=" + threadState + + ", stackTrace=" + Arrays.toString(stackTrace) + + ", allocatedBytes=" + allocatedBytes + + ", threadCpuTime=" + threadCpuTime + ", threadUserTime=" + + threadUserTime + ", blockedCount=" + blockedCount + + ", waitedCount=" + waitedCount + ", timestamp=" + timestamp + + "]"; + } + + public void setName(String threadName) { + this.name = threadName; + } + + public void setID(long threadID) { + this.threadID = threadID; + } + + public void setState(State threadState) { + this.threadState = threadState; + } + + public void setAllocatedBytes(long allocatedBytes) { + this.allocatedBytes = allocatedBytes; + } + + public String getName() { + return name; + } + + public long getAllocatedBytes() { + return allocatedBytes; + } + + public long getThreadID() { + return threadID; + } + + public State getState() { + return threadState; + } + + public long getTimeStamp() { + return timestamp; + } + + public void setTimeStamp(long timestamp) { + this.timestamp = timestamp; + } + + public void setCPUTime(long threadCpuTime) { + this.threadCpuTime = threadCpuTime; + } + + public void setUserTime(long threadUserTime) { + this.threadUserTime = threadUserTime; + } + + public void setBlockedCount(long blockedCount) { + this.blockedCount = blockedCount; + } + + public void setWaitedCount(long waitedCount) { + this.waitedCount = waitedCount; + } + + public long getBlockedCount() { + return blockedCount; + } + + public long getWaitedCount() { + return waitedCount; + } + + public long getCpuTime() { + return threadCpuTime; + } + + public long getUserTime() { + return threadUserTime; + } + + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + (int) (threadID ^ (threadID >>> 32)); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ThreadInfoData other = (ThreadInfoData) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (threadID != other.threadID) + return false; + return true; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/ThreadSummary.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are 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.model; + +import com.redhat.thermostat.common.model.TimeStampedPojo; + + +public class ThreadSummary implements TimeStampedPojo { + + private long currentLiveThreads; + private long daemonThreads; + + private long timestamp; + + public long currentLiveThreads() { + return currentLiveThreads; + } + + public void setCurrentLiveThreads(long currentLiveThreads) { + this.currentLiveThreads = currentLiveThreads; + } + + public long currentDaemonThreads() { + return daemonThreads; + } + + public void setDaemonThreads(long daemonThreads) { + this.daemonThreads = daemonThreads; + } + + public long getTimeStamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + @Override + public String toString() { + return "[timestamp: " + timestamp + ", currentLiveThreads: " + + currentLiveThreads + ", daemonThreads: " + daemonThreads + "]"; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/model/VMThreadCapabilities.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,74 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are 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.model; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.redhat.thermostat.thread.dao.ThreadDao; + +public class VMThreadCapabilities { + + private Set<String> features = new HashSet<>(); + + public boolean supportCPUTime() { + return features.contains(ThreadDao.CPU_TIME); + } + + public boolean supportContentionMonitor() { + return features.contains(ThreadDao.CONTENTION_MONITOR); + } + + public String toString() { + return "[supportCPU: " + supportCPUTime() + ", supportContention: " + supportContentionMonitor() + + ", supportThreadAllocatedMemory: " + supportThreadAllocatedMemory() + "]"; + } + + public boolean supportThreadAllocatedMemory() { + return features.contains(ThreadDao.THREAD_ALLOCATED_MEMORY); + } + + public List<String> getSupportedFeaturesList() { + return new ArrayList<>(features); + } + + public void addFeature(String feature) { + features.add(feature); + } +}
--- a/thread/collector/src/main/java/com/redhat/thermostat/utils/management/MXBeanConnection.java Fri Aug 31 11:22:52 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are 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.management; - -import java.io.Closeable; -import java.io.IOException; - -import javax.management.JMX; -import javax.management.MBeanServerConnection; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; -import javax.management.remote.JMXConnector; - -public class MXBeanConnection implements Closeable { - - private JMXConnector connection; - private MBeanServerConnection mbsc; - - MXBeanConnection(JMXConnector connection, MBeanServerConnection mbsc) { - this.connection = connection; - this.mbsc = mbsc; - } - - public synchronized <E> E createProxy(String name, Class<? extends E> proxyClass) throws MalformedObjectNameException { - ObjectName objectName = new ObjectName(name); - return JMX.newMXBeanProxy(mbsc, objectName, proxyClass); - } - - @Override - public void close() throws IOException { - connection.close(); - } -}
--- a/thread/collector/src/main/java/com/redhat/thermostat/utils/management/MXBeanConnector.java Fri Aug 31 11:22:52 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are 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.management; - -import java.io.Closeable; -import java.io.File; -import java.io.IOException; -import java.util.Properties; - -import javax.management.MBeanServerConnection; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXServiceURL; - -import com.redhat.thermostat.common.dao.VmRef; -import com.sun.tools.attach.VirtualMachine; - -public class MXBeanConnector implements Closeable { - - private static final String CONNECTOR_ADDRESS_PROPERTY = "com.sun.management.jmxremote.localConnectorAddress"; - private String connectorAddress; - - private VmRef reference; - private VirtualMachine vm; - - private boolean attached; - - public MXBeanConnector(VmRef reference) { - this.reference = reference; - } - - public synchronized void attach() throws Exception { - if (attached) - throw new IOException("Already attached"); - - vm = VirtualMachine.attach(reference.getStringID()); - attached = true; - - Properties props = vm.getAgentProperties(); - connectorAddress = props.getProperty(CONNECTOR_ADDRESS_PROPERTY); - if (connectorAddress == null) { - props = vm.getSystemProperties(); - String home = props.getProperty("java.home"); - String agent = home + File.separator + "lib" + File.separator + "management-agent.jar"; - vm.loadAgent(agent); - - props = vm.getAgentProperties(); - connectorAddress = props.getProperty(CONNECTOR_ADDRESS_PROPERTY); - } - } - - public synchronized MXBeanConnection connect() throws Exception { - - if (!attached) - throw new IOException("Agent not attached to target VM"); - - JMXServiceURL url = new JMXServiceURL(connectorAddress); - JMXConnector connection = JMXConnectorFactory.connect(url); - MBeanServerConnection mbsc = null; - try { - mbsc = connection.getMBeanServerConnection(); - - } catch (IOException e) { - connection.close(); - throw e; - } - - return new MXBeanConnection(connection, mbsc); - } - - public boolean isAttached() { - return attached; - } - - @Override - public synchronized void close() throws IOException { - if (attached) { - vm.detach(); - attached = false; - } - } -}
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/collector/ThreadCollectorFactoryTest.java Fri Aug 31 11:22:52 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are 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.collector; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.mock; - -import java.util.concurrent.ScheduledExecutorService; - -import org.junit.Test; - -import com.redhat.thermostat.common.dao.VmRef; -import com.redhat.thermostat.thread.collector.impl.ThreadCollectorFactoryImpl; -import com.redhat.thermostat.thread.dao.ThreadDao; - -public class ThreadCollectorFactoryTest { - - @Test - public void testThreadCollectorFactory() { - ThreadDao threadDao = mock(ThreadDao.class); - VmRef reference = mock(VmRef.class); - - ScheduledExecutorService threadPool = mock(ScheduledExecutorService.class); - - ThreadCollectorFactory factory = new ThreadCollectorFactoryImpl(threadDao, threadPool); - ThreadCollector collector = factory.getCollector(reference); - assertNotNull(collector); - - // ask again, it must be the same instance as before - ThreadCollector collector2 = factory.getCollector(reference); - assertSame(collector, collector2); - - // and now of course it must be different - VmRef reference2 = mock(VmRef.class); - ThreadCollector collector3 = factory.getCollector(reference2); - assertNotSame(collector, collector3); - } -}
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/collector/ThreadCollectorTest.java Fri Aug 31 11:22:52 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,204 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are 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.collector; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.lang.management.ManagementFactory; -import java.lang.management.ThreadMXBean; -import java.util.concurrent.ScheduledExecutorService; - -import javax.management.MalformedObjectNameException; - -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.redhat.thermostat.common.dao.VmRef; -import com.redhat.thermostat.thread.collector.impl.ThreadMXBeanCollector; -import com.redhat.thermostat.thread.dao.ThreadDao; -import com.redhat.thermostat.utils.management.MXBeanConnection; -import com.redhat.thermostat.utils.management.MXBeanConnector; - -public class ThreadCollectorTest { - - @Test - public void testVMCapabilitiesNotInDAO() throws Exception { - - VMThreadCapabilities referenceCaps = mock(VMThreadCapabilities.class); - when(referenceCaps.supportContentionMonitor()).thenReturn(true); - when(referenceCaps.supportCPUTime()).thenReturn(false); - - VmRef reference = mock(VmRef.class); - - ThreadDao threadDao = mock(ThreadDao.class); - when(threadDao.loadCapabilities(reference)).thenReturn(null); - - MXBeanConnector connector = mock(MXBeanConnector.class); - when(connector.isAttached()).thenReturn(false).thenReturn(true); - - MXBeanConnection connection = mock(MXBeanConnection.class); - when(connector.connect()).thenReturn(connection); - - ArgumentCaptor<String> captor1 = ArgumentCaptor.forClass(String.class); - ArgumentCaptor<Class> captor2 = ArgumentCaptor.forClass(Class.class); - - ThreadMXBean bean = mock(ThreadMXBean.class); - when(bean.isThreadCpuTimeSupported()).thenReturn(false); - when(bean.isThreadContentionMonitoringSupported()).thenReturn(true); - - when(connection.createProxy(captor1.capture(), captor2.capture())).thenThrow(new MalformedObjectNameException()).thenReturn(bean); - - ScheduledExecutorService threadPool = mock(ScheduledExecutorService.class); - - /* ************* */ - - ThreadCollector collector = new ThreadMXBeanCollector(threadDao, reference, connector, threadPool); - VMThreadCapabilities caps = collector.getVMThreadCapabilities(); - - String beanName = captor1.getValue(); - assertEquals(ManagementFactory.THREAD_MXBEAN_NAME, beanName); - - Class clazz = captor2.getValue(); - assertEquals(ThreadMXBean.class.getName(), clazz.getName()); - - verify(threadDao).loadCapabilities(reference); - - verify(connector).attach(); - verify(connector).connect(); - verify(connector).close(); - - verify(threadDao).saveCapabilities(reference, caps); - - assertTrue(caps.supportContentionMonitor()); - assertFalse(caps.supportCPUTime()); - assertFalse(caps.supportThreadAllocatedMemory()); - } - - @SuppressWarnings("restriction") - @Test - public void testHasThreadMemorySupport() throws Exception { - - VMThreadCapabilities referenceCaps = mock(VMThreadCapabilities.class); - when(referenceCaps.supportContentionMonitor()).thenReturn(true); - when(referenceCaps.supportCPUTime()).thenReturn(false); - - VmRef reference = mock(VmRef.class); - - ThreadDao threadDao = mock(ThreadDao.class); - when(threadDao.loadCapabilities(reference)).thenReturn(null); - - MXBeanConnector connector = mock(MXBeanConnector.class); - when(connector.isAttached()).thenReturn(false).thenReturn(true); - - MXBeanConnection connection = mock(MXBeanConnection.class); - when(connector.connect()).thenReturn(connection); - - ArgumentCaptor<String> captor1 = ArgumentCaptor.forClass(String.class); - ArgumentCaptor<Class> captor2 = ArgumentCaptor.forClass(Class.class); - - com.sun.management.ThreadMXBean bean = mock(com.sun.management.ThreadMXBean.class); - when(bean.isThreadCpuTimeSupported()).thenReturn(false); - when(bean.isThreadContentionMonitoringSupported()).thenReturn(true); - when(bean.isThreadAllocatedMemorySupported()).thenReturn(true); - - when(connection.createProxy(captor1.capture(), captor2.capture())).thenReturn(bean); - - ScheduledExecutorService threadPool = mock(ScheduledExecutorService.class); - - /* ************* */ - - ThreadCollector collector = new ThreadMXBeanCollector(threadDao, reference, connector, threadPool); - VMThreadCapabilities caps = collector.getVMThreadCapabilities(); - - String beanName = captor1.getValue(); - assertEquals(ManagementFactory.THREAD_MXBEAN_NAME, beanName); - - Class clazz = captor2.getValue(); - assertEquals(com.sun.management.ThreadMXBean.class.getName(), clazz.getName()); - - verify(threadDao).loadCapabilities(reference); - - verify(connector).attach(); - verify(connector).connect(); - verify(connector).close(); - - verify(threadDao).saveCapabilities(reference, caps); - - assertTrue(caps.supportContentionMonitor()); - assertFalse(caps.supportCPUTime()); - assertTrue(caps.supportThreadAllocatedMemory()); - } - - @Test - public void testVMCapabilitiesInDAO() throws Exception { - - VMThreadCapabilities referenceCaps = mock(VMThreadCapabilities.class); - when(referenceCaps.supportContentionMonitor()).thenReturn(true); - when(referenceCaps.supportCPUTime()).thenReturn(false); - - VmRef reference = mock(VmRef.class); - - ThreadDao threadDao = mock(ThreadDao.class); - when(threadDao.loadCapabilities(reference)).thenReturn(referenceCaps); - - MXBeanConnector connector = mock(MXBeanConnector.class); - - ScheduledExecutorService threadPool = mock(ScheduledExecutorService.class); - - /* ************* */ - - ThreadCollector collector = new ThreadMXBeanCollector(threadDao, reference, connector, threadPool); - VMThreadCapabilities caps = collector.getVMThreadCapabilities(); - - verify(threadDao).loadCapabilities(reference); - - verify(connector, times(0)).attach(); - verify(connector, times(0)).connect(); - verify(connector, times(0)).close(); - - verify(threadDao, times(0)).saveCapabilities(reference, caps); - - assertTrue(caps.supportContentionMonitor()); - assertFalse(caps.supportCPUTime()); - } -}
--- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java Fri Aug 31 11:22:52 2012 +0200 +++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -52,8 +52,8 @@ import com.redhat.thermostat.common.storage.Chunk; import com.redhat.thermostat.common.storage.Key; import com.redhat.thermostat.common.storage.Storage; -import com.redhat.thermostat.thread.collector.VMThreadCapabilities; import com.redhat.thermostat.thread.dao.ThreadDao; +import com.redhat.thermostat.thread.model.VMThreadCapabilities; public class ThreadDaoImplTest { @@ -61,7 +61,9 @@ public void testCreateConnectionKey() { Storage storage = mock(Storage.class); + @SuppressWarnings("unused") ThreadDaoImpl dao = new ThreadDaoImpl(storage); + verify(storage).createConnectionKey(ThreadDao.THREAD_CAPABILITIES); verify(storage).createConnectionKey(ThreadDao.THREAD_INFO); verify(storage).createConnectionKey(ThreadDao.THREAD_SUMMARY); @@ -102,14 +104,6 @@ public void testSaveVMCapabilities() { Storage storage = mock(Storage.class); - VmRef ref = mock(VmRef.class); - when(ref.getId()).thenReturn(42); - - HostRef agent = mock(HostRef.class); - when(agent.getAgentId()).thenReturn("0xcafe"); - - when(ref.getAgent()).thenReturn(agent); - Chunk answer = mock(Chunk.class); when(answer.get(ThreadDao.CONTENTION_MONITOR_KEY)).thenReturn(false); when(answer.get(ThreadDao.CPU_TIME_KEY)).thenReturn(true); @@ -120,7 +114,7 @@ when(caps.supportThreadAllocatedMemory()).thenReturn(true); ThreadDaoImpl dao = new ThreadDaoImpl(storage); - dao.saveCapabilities(ref, caps); + dao.saveCapabilities("42", "0xcafe", caps); ArgumentCaptor<Chunk> queryCaptor = ArgumentCaptor.forClass(Chunk.class); verify(storage).putChunk(queryCaptor.capture());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/harvester/pom.xml Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Copyright 2012 Red Hat, Inc. + + This file is part of Thermostat. + + Thermostat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + Thermostat is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Thermostat; see the file COPYING. If not see + <http://www.gnu.org/licenses />. + + Linking this code with other modules is making a combined work + based on this code. Thus, the terms and conditions of the GNU + General Public License cover the whole combination. + + As a special exception, the copyright holders of this code give + you permission to link this code with independent modules to + produce an executable, regardless of the license terms of these + independent modules, and to copy and distribute the resulting + executable under terms of your choice, provided that you also + meet, for each linked independent module, the terms and conditions + of the license of that module. An independent module is a module + which is not derived from or based on this code. If you modify + this code, you may extend this exception to your version of the + library, but you are not obligated to do so. If you do not wish + to do so, delete this exception statement from your version. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-thread</artifactId> + <version>0.4.0-SNAPSHOT</version> + </parent> + + <artifactId>thermostat-thread-harvester</artifactId> + <packaging>bundle</packaging> + + <name>Thermostat Thread Info Harvester</name> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-thread-collector</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.core</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.compendium</artifactId> + <scope>provided</scope> + </dependency> + + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor> + <Bundle-Activator>com.redhat.thermostat.thread.harvester.osgi.Activator</Bundle-Activator> + <Bundle-SymbolicName>com.redhat.thermostat.thread.harvester</Bundle-SymbolicName> + <Private-Package> + com.redhat.thermostat.thread.harvester, + com.redhat.thermostat.thread.harvester.management, + com.redhat.thermostat.thread.harvester.osgi, + </Private-Package> + <!-- Do not autogenerate uses clauses in Manifests --> + <_nouses>true</_nouses> + </instructions> + </configuration> + </plugin> + </plugins> + </build> + +</project>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/Harvester.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,287 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are 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.harvester; + +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.management.MalformedObjectNameException; + +import com.redhat.thermostat.thread.dao.ThreadDao; +import com.redhat.thermostat.thread.harvester.management.MXBeanConnection; +import com.redhat.thermostat.thread.harvester.management.MXBeanConnector; +import com.redhat.thermostat.thread.model.ThreadInfoData; +import com.redhat.thermostat.thread.model.ThreadSummary; +import com.redhat.thermostat.thread.model.VMThreadCapabilities; + +@SuppressWarnings("restriction") +class Harvester { + + private static final Logger logger = Logger.getLogger(Harvester.class.getSimpleName()); + + private boolean isConnected; + private ScheduledExecutorService threadPool; + private ScheduledFuture<?> harvester; + + MXBeanConnector connector; + + private MXBeanConnection connection; + private ThreadMXBean collectorBean; + private ThreadDao threadDao; + private String vmId; + private String agentId; + + Harvester(ThreadDao threadDao, ScheduledExecutorService threadPool, String vmId, String agentId) { + this.connector = new MXBeanConnector(vmId); + this.threadDao = threadDao; + this.vmId = vmId; + this.agentId = agentId; + this.threadPool = threadPool; + } + + synchronized boolean start() { + if (isConnected) { + return true; + } + + if (!connector.isAttached()) { + try { + connector.attach(); + } catch (Exception ex) { + logger.log(Level.SEVERE, "can't attach", ex); + return false; + } + } + + try { + connection = connector.connect(); + } catch (Exception ex) { + logger.log(Level.SEVERE, "can't connect", ex); + return false; + } + + isConnected = true; + harvester = threadPool.scheduleAtFixedRate(new HarvesterAction(), 0, 1, TimeUnit.SECONDS); + + return isConnected; + } + + boolean isConnected() { + return isConnected; + } + + synchronized boolean stop() { + if (!isConnected) { + return true; + } + + harvester.cancel(false); + isConnected = false; + + boolean stillConnected = false; + try { + connection.close(); + } catch (IOException ex) { + logger.log(Level.SEVERE, "can't close connection", ex); + stillConnected = true; + } + + if (connector.isAttached()) { + try { + connector.close(); + } catch (Exception ex) { + logger.log(Level.SEVERE, "can't detach", ex); + if (stillConnected) { + isConnected = true; + } + return false; + } + } + + return true; + } + + ThreadMXBean getDataCollectorBean(MXBeanConnection connection) + throws MalformedObjectNameException + { + ThreadMXBean bean = null; + try { + bean = connection.createProxy(ManagementFactory.THREAD_MXBEAN_NAME, + com.sun.management.ThreadMXBean.class); + } catch (MalformedObjectNameException ignore) {} + + if (bean == null) { + bean = connection.createProxy(ManagementFactory.THREAD_MXBEAN_NAME, + ThreadMXBean.class); + } + return bean; + } + + synchronized void harvestData() { + try { + long timestamp = System.currentTimeMillis(); + + ThreadSummary summary = new ThreadSummary(); + + collectorBean = getDataCollectorBean(connection); + + summary.setCurrentLiveThreads(collectorBean.getThreadCount()); + summary.setDaemonThreads(collectorBean.getDaemonThreadCount()); + summary.setTimestamp(timestamp); + + threadDao.saveSummary(vmId, agentId, summary); + + long [] ids = collectorBean.getAllThreadIds(); + long[] allocatedBytes = null; + + // now the details for the threads + if (collectorBean instanceof com.sun.management.ThreadMXBean) { + com.sun.management.ThreadMXBean sunBean = (com.sun.management.ThreadMXBean) collectorBean; + boolean wasEnabled = false; + try { + if (sunBean.isThreadAllocatedMemorySupported()) { + wasEnabled = sunBean.isThreadAllocatedMemoryEnabled(); + sunBean.setThreadAllocatedMemoryEnabled(true); + allocatedBytes = sunBean.getThreadAllocatedBytes(ids); + sunBean.setThreadAllocatedMemoryEnabled(wasEnabled); + } + } catch (Exception ignore) {} + } + + ThreadInfo[] threadInfos = collectorBean.getThreadInfo(ids, true, true); + + for (int i = 0; i < ids.length; i++) { + ThreadInfoData info = new ThreadInfoData(); + ThreadInfo beanInfo = threadInfos[i]; + + info.setTimeStamp(timestamp); + + info.setName(beanInfo.getThreadName()); + info.setID(beanInfo.getThreadId()); + info.setState(beanInfo.getThreadState()); + info.setStackTrace(beanInfo.getStackTrace()); + + info.setCPUTime(collectorBean.getThreadCpuTime(info.getThreadID())); + info.setUserTime(collectorBean.getThreadUserTime(info.getThreadID())); + + info.setBlockedCount(beanInfo.getBlockedCount()); + info.setWaitedCount(beanInfo.getWaitedCount()); + + if (allocatedBytes != null) { + info.setAllocatedBytes(allocatedBytes[i]); + } + + threadDao.saveThreadInfo(vmId, agentId, info); + } + + } catch (MalformedObjectNameException e) { + e.printStackTrace(); + } + } + + private class HarvesterAction implements Runnable { + @Override + public void run() { + harvestData(); + } + } + + synchronized boolean saveVmCaps() { + + boolean closeAfter = false; + if (!connector.isAttached()) { + closeAfter = true; + try { + connector.attach(); + } catch (Exception ex) { + logger.log(Level.SEVERE, "can't attach", ex); + if (closeAfter) { + closeConnection(); + } + return false; + } + } + + try (MXBeanConnection connection = connector.connect()) { + + ThreadMXBean bean = getDataCollectorBean(connection); + VMThreadCapabilities caps = new VMThreadCapabilities(); + + if (bean.isThreadCpuTimeSupported()) + caps.addFeature(ThreadDao.CPU_TIME); + if (bean.isThreadContentionMonitoringSupported()) + caps.addFeature(ThreadDao.CONTENTION_MONITOR); + + if (bean instanceof com.sun.management.ThreadMXBean) { + com.sun.management.ThreadMXBean sunBean = (com.sun.management.ThreadMXBean) bean; + + try { + if (sunBean.isThreadAllocatedMemorySupported()) { + caps.addFeature(ThreadDao.THREAD_ALLOCATED_MEMORY); + } + } catch (Exception ignore) {}; + } + + threadDao.saveCapabilities(vmId, agentId, caps); + + } catch (Exception ex) { + logger.log(Level.SEVERE, "can't get MXBeanConnection connection", ex); + return false; + } + + if (closeAfter) { + closeConnection(); + } + + return true; + } + + private void closeConnection() { + try { + connector.close(); + } catch (Exception ex) { + logger.log(Level.SEVERE, "can't close connection to vm", ex); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/ThreadHarvester.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,142 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are 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.harvester; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ScheduledExecutorService; + +import com.redhat.thermostat.agent.command.RequestReceiver; +import com.redhat.thermostat.common.command.Request; +import com.redhat.thermostat.common.command.Response; +import com.redhat.thermostat.common.command.Response.ResponseType; + +import com.redhat.thermostat.thread.collector.HarvesterCommand; +import com.redhat.thermostat.thread.dao.ThreadDao; + +public class ThreadHarvester implements RequestReceiver { + + private ScheduledExecutorService executor; + Map<String, Harvester> connectors; + + private ThreadDao dao; + + public ThreadHarvester(ScheduledExecutorService executor, ThreadDao dao) { + this.executor = executor; + connectors = new HashMap<>(); + this.dao = dao; + } + + @Override + public Response receive(Request request) { + + boolean result = false; + + String command = request.getParameter(HarvesterCommand.class.getName()); + switch (HarvesterCommand.valueOf(command)) { + case START: { + String vmId = request.getParameter(HarvesterCommand.VM_ID.name()); + String agentId = request.getParameter(HarvesterCommand.AGENT_ID.name()); + result = startHarvester(vmId, agentId); + break; + } + case STOP: { + String vmId = request.getParameter(HarvesterCommand.VM_ID.name()); + result = stopHarvester(vmId); + break; + } + case VM_CAPS: { + // this is blocking + String vmId = request.getParameter(HarvesterCommand.VM_ID.name()); + String agentId = request.getParameter(HarvesterCommand.AGENT_ID.name()); + result = saveVmCaps(vmId, agentId); + break; + } + case IS_COLLECTING: { + // this is blocking too + String vmId = request.getParameter(HarvesterCommand.VM_ID.name()); + // FIXME: this need to be replaced when we support response parameters + return isCollecting(vmId) ? new Response(ResponseType.OK) : new Response(ResponseType.NOK); + } + default: + result = false; + break; + } + + if (result) { + return new Response(ResponseType.OK); + } else { + return new Response(ResponseType.ERROR); + } + } + + private boolean isCollecting(String vmId) { + Harvester harvester = connectors.get(vmId); + if (harvester == null) { + return false; + } + return harvester.isConnected(); + } + + private boolean startHarvester(String vmId, String agentId) { + Harvester harvester = getHarvester(vmId, agentId); + return harvester.start(); + } + + private boolean saveVmCaps(String vmId, String agentId) { + Harvester harvester = getHarvester(vmId, agentId); + return harvester.saveVmCaps(); + } + + private boolean stopHarvester(String vmId) { + Harvester harvester = connectors.get(vmId); + if (harvester != null) { + return harvester.stop(); + } + return true; + } + + Harvester getHarvester(String vmId, String agentId) { + Harvester harvester = connectors.get(vmId); + if (harvester == null) { + harvester = new Harvester(dao, executor, vmId, agentId); + connectors.put(vmId, harvester); + } + + return harvester; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/management/MXBeanConnection.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,67 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are 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.harvester.management; + +import java.io.Closeable; +import java.io.IOException; + +import javax.management.JMX; +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; + +public class MXBeanConnection implements Closeable { + + private JMXConnector connection; + private MBeanServerConnection mbsc; + + MXBeanConnection(JMXConnector connection, MBeanServerConnection mbsc) { + this.connection = connection; + this.mbsc = mbsc; + } + + public synchronized <E> E createProxy(String name, Class<? extends E> proxyClass) throws MalformedObjectNameException { + ObjectName objectName = new ObjectName(name); + return JMX.newMXBeanProxy(mbsc, objectName, proxyClass); + } + + @Override + public void close() throws IOException { + connection.close(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/management/MXBeanConnector.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,121 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are 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.harvester.management; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.util.Properties; + +import javax.management.MBeanServerConnection; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +import com.redhat.thermostat.common.dao.VmRef; +import com.sun.tools.attach.VirtualMachine; + +public class MXBeanConnector implements Closeable { + + private static final String CONNECTOR_ADDRESS_PROPERTY = "com.sun.management.jmxremote.localConnectorAddress"; + private String connectorAddress; + + private VirtualMachine vm; + + private boolean attached; + + private String reference; + + public MXBeanConnector(String reference) { + this.reference = reference; + } + + public MXBeanConnector(VmRef reference) { + this.reference = reference.getStringID(); + } + + public synchronized void attach() throws Exception { + if (attached) + throw new IOException("Already attached"); + + vm = VirtualMachine.attach(reference); + attached = true; + + Properties props = vm.getAgentProperties(); + connectorAddress = props.getProperty(CONNECTOR_ADDRESS_PROPERTY); + if (connectorAddress == null) { + props = vm.getSystemProperties(); + String home = props.getProperty("java.home"); + String agent = home + File.separator + "lib" + File.separator + "management-agent.jar"; + vm.loadAgent(agent); + + props = vm.getAgentProperties(); + connectorAddress = props.getProperty(CONNECTOR_ADDRESS_PROPERTY); + } + } + + public synchronized MXBeanConnection connect() throws Exception { + + if (!attached) + throw new IOException("Agent not attached to target VM"); + + JMXServiceURL url = new JMXServiceURL(connectorAddress); + JMXConnector connection = JMXConnectorFactory.connect(url); + MBeanServerConnection mbsc = null; + try { + mbsc = connection.getMBeanServerConnection(); + + } catch (IOException e) { + connection.close(); + throw e; + } + + return new MXBeanConnection(connection, mbsc); + } + + public boolean isAttached() { + return attached; + } + + @Override + public synchronized void close() throws IOException { + if (attached) { + vm.detach(); + attached = false; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/harvester/src/main/java/com/redhat/thermostat/thread/harvester/osgi/Activator.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,80 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are 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.harvester.osgi; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTracker; + +import com.redhat.thermostat.agent.command.ReceiverRegistry; +import com.redhat.thermostat.thread.dao.ThreadDao; +import com.redhat.thermostat.thread.harvester.ThreadHarvester; + +public class Activator implements BundleActivator { + + private ScheduledExecutorService executor = Executors.newScheduledThreadPool(24); + + @Override + public void start(final BundleContext context) throws Exception { + @SuppressWarnings({ "rawtypes", "unchecked" }) + ServiceTracker tracker = new ServiceTracker(context, ThreadDao.class.getName(), null) { + @Override + public Object addingService(ServiceReference reference) { + ThreadDao threadDao = (ThreadDao) context.getService(reference); + + ThreadHarvester harvester = new ThreadHarvester(executor, threadDao); + + ReceiverRegistry registry = new ReceiverRegistry(context); + registry.registerReceiver(harvester); + + return super.addingService(reference); + } + }; + tracker.open(); + } + + @Override + public void stop(BundleContext context) throws Exception { + if (executor != null) { + executor.shutdown(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/HarvesterTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,400 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are 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.harvester; + +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 static org.mockito.Mockito.when; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.doNothing; + +import static org.junit.Assert.*; + +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.util.List; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import javax.management.MalformedObjectNameException; + +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.thread.dao.ThreadDao; +import com.redhat.thermostat.thread.harvester.management.MXBeanConnection; +import com.redhat.thermostat.thread.harvester.management.MXBeanConnector; +import com.redhat.thermostat.thread.model.ThreadInfoData; +import com.redhat.thermostat.thread.model.ThreadSummary; +import com.redhat.thermostat.thread.model.VMThreadCapabilities; + +public class HarvesterTest { + + @Test + public void testStart() { + ScheduledExecutorService executor = mock(ScheduledExecutorService.class); + ThreadDao dao = mock(ThreadDao.class); + final MXBeanConnector mockedConnector = mock(MXBeanConnector.class); + when(mockedConnector.isAttached()).thenReturn(false); + + ArgumentCaptor<Runnable> arg0 = ArgumentCaptor.forClass(Runnable.class); + ArgumentCaptor<Long> arg1 = ArgumentCaptor.forClass(Long.class); + ArgumentCaptor<Long> arg2 = ArgumentCaptor.forClass(Long.class); + ArgumentCaptor<TimeUnit> arg3 = ArgumentCaptor.forClass(TimeUnit.class); + + final boolean [] harvestDataCalled = new boolean[1]; + + when(executor.scheduleAtFixedRate(arg0.capture(), arg1.capture(), arg2.capture(), arg3.capture())).thenReturn(null); + + Harvester harvester = new Harvester(dao, executor, "42", "0xcafe") { + { connector = mockedConnector; } + @Override + synchronized void harvestData() { + harvestDataCalled[0] = true; + } + }; + + harvester.start(); + + verify(executor).scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class)); + + assertTrue(arg1.getValue() == 0); + assertTrue(arg2.getValue() == 1); + assertEquals(TimeUnit.SECONDS, arg3.getValue()); + + Runnable action = arg0.getValue(); + assertNotNull(action); + + action.run(); + + assertTrue(harvestDataCalled[0]); + + assertTrue(harvester.isConnected()); + } + + /** + * Mostly the same as testStart, but we call harvester.start() twice + */ + @Test + public void testStartOnce() throws Exception { + + ScheduledExecutorService executor = mock(ScheduledExecutorService.class); + ThreadDao dao = mock(ThreadDao.class); + final MXBeanConnector mockedConnector = mock(MXBeanConnector.class); + when(mockedConnector.isAttached()).thenReturn(false); + + ArgumentCaptor<Runnable> arg0 = ArgumentCaptor.forClass(Runnable.class); + ArgumentCaptor<Long> arg1 = ArgumentCaptor.forClass(Long.class); + ArgumentCaptor<Long> arg2 = ArgumentCaptor.forClass(Long.class); + ArgumentCaptor<TimeUnit> arg3 = ArgumentCaptor.forClass(TimeUnit.class); + + final boolean [] harvestDataCalled = new boolean[1]; + + when(executor.scheduleAtFixedRate(arg0.capture(), arg1.capture(), arg2.capture(), arg3.capture())).thenReturn(null); + + Harvester harvester = new Harvester(dao, executor, "42", "0xcafe") { + { connector = mockedConnector; } + @Override + synchronized void harvestData() { + harvestDataCalled[0] = true; + } + }; + + harvester.start(); + harvester.start(); + + verify(mockedConnector, times(1)).isAttached(); + verify(mockedConnector, times(1)).attach(); + verify(executor, times(1)).scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class)); + + assertTrue(arg1.getValue() == 0); + assertTrue(arg2.getValue() == 1); + assertEquals(TimeUnit.SECONDS, arg3.getValue()); + + Runnable action = arg0.getValue(); + assertNotNull(action); + + action.run(); + + assertTrue(harvestDataCalled[0]); + + assertTrue(harvester.isConnected()); + } + + @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void testStopAfterStarting() throws Exception { + + ScheduledFuture future = mock(ScheduledFuture.class); + + ScheduledExecutorService executor = mock(ScheduledExecutorService.class); + ThreadDao dao = mock(ThreadDao.class); + final MXBeanConnector mockedConnector = mock(MXBeanConnector.class); + + MXBeanConnection connection = mock(MXBeanConnection.class); + + when(mockedConnector.connect()).thenReturn(connection); + + when(mockedConnector.isAttached()).thenReturn(true); + + when(executor.scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class))).thenReturn(future); + + Harvester harvester = new Harvester(dao, executor, "42", "0xcafe") + {{ connector = mockedConnector; }}; + + harvester.start(); + + assertTrue(harvester.isConnected()); + + harvester.stop(); + + verify(future).cancel(false); + verify(connection).close(); + + // needs to be 2 times, since is called once in start + verify(mockedConnector, times(2)).isAttached(); + verify(mockedConnector).close(); + + assertFalse(harvester.isConnected()); + } + + /** + * Mostly the same as testStopAfterStarting, but we call harvester.stop() + * twice + */ + @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void testStopTwiceAfterStarting() throws Exception { + + ScheduledFuture future = mock(ScheduledFuture.class); + + ScheduledExecutorService executor = mock(ScheduledExecutorService.class); + ThreadDao dao = mock(ThreadDao.class); + final MXBeanConnector mockedConnector = mock(MXBeanConnector.class); + + MXBeanConnection connection = mock(MXBeanConnection.class); + + when(mockedConnector.connect()).thenReturn(connection); + + when(mockedConnector.isAttached()).thenReturn(true); + + when(executor.scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class))).thenReturn(future); + + Harvester harvester = new Harvester(dao, executor, "42", "0xcafe") + {{ connector = mockedConnector; }}; + + harvester.start(); + + assertTrue(harvester.isConnected()); + + harvester.stop(); + harvester.stop(); + + verify(future, times(1)).cancel(false); + verify(connection, times(1)).close(); + + // needs to be 2 times, since is called once in start + verify(mockedConnector, times(2)).isAttached(); + + verify(mockedConnector, times(1)).close(); + + assertFalse(harvester.isConnected()); + } + + @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void testStopNotStarted() throws Exception { + ScheduledExecutorService executor = mock(ScheduledExecutorService.class); + ThreadDao dao = mock(ThreadDao.class); + + ScheduledFuture future = mock(ScheduledFuture.class); + when(executor.scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class))).thenReturn(future); + + final MXBeanConnector mockedConnector = mock(MXBeanConnector.class); + MXBeanConnection connection = mock(MXBeanConnection.class); + when(mockedConnector.connect()).thenReturn(connection); + when(mockedConnector.isAttached()).thenReturn(true); + + Harvester harvester = new Harvester(dao, executor, "42", "0xcafe") + {{ connector = mockedConnector; }}; + + verify(executor, times(0)).scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class)); + + assertFalse(harvester.isConnected()); + + harvester.stop(); + + assertFalse(harvester.isConnected()); + verify(mockedConnector, times(0)).isAttached(); + + verify(future, times(0)).cancel(false); + } + + @Test + public void testHarvestData() { + + long ids[] = new long [] { + 0, 1 + }; + + ThreadInfo info1 = mock(ThreadInfo.class); + when(info1.getThreadName()).thenReturn("fluff1"); + when(info1.getThreadId()).thenReturn(1l); + + ThreadInfo info2 = mock(ThreadInfo.class); + when(info2.getThreadName()).thenReturn("fluff2"); + when(info2.getThreadId()).thenReturn(2l); + + ThreadInfo[] infos = new ThreadInfo[] { + info1, + info2 + }; + + ScheduledExecutorService executor = mock(ScheduledExecutorService.class); + + ArgumentCaptor<String> vmCapture = ArgumentCaptor.forClass(String.class); + ArgumentCaptor<String> agentCapture = ArgumentCaptor.forClass(String.class); + ArgumentCaptor<ThreadSummary> summaryCapture = ArgumentCaptor.forClass(ThreadSummary.class); + + ThreadDao dao = mock(ThreadDao.class); + doNothing().when(dao).saveSummary(vmCapture.capture(), agentCapture.capture(), summaryCapture.capture()); + + ArgumentCaptor<String> vmCapture2 = ArgumentCaptor.forClass(String.class); + ArgumentCaptor<String> agentCapture2 = ArgumentCaptor.forClass(String.class); + ArgumentCaptor<ThreadInfoData> threadInfoCapture = ArgumentCaptor.forClass(ThreadInfoData.class); + doNothing().when(dao).saveThreadInfo(vmCapture2.capture(), agentCapture2.capture(), threadInfoCapture.capture()); + + final ThreadMXBean collectorBean = mock(ThreadMXBean.class); + + when(collectorBean.getThreadCount()).thenReturn(42); + when(collectorBean.getAllThreadIds()).thenReturn(ids); + when(collectorBean.getThreadInfo(ids, true, true)).thenReturn(infos); + + final boolean [] getDataCollectorBeanCalled = new boolean[1]; + + Harvester harvester = new Harvester(dao, executor, "42", "0xcafe") { + @Override + ThreadMXBean getDataCollectorBean(MXBeanConnection connection) + throws MalformedObjectNameException { + getDataCollectorBeanCalled[0] = true; + return collectorBean; + } + }; + + harvester.harvestData(); + + assertTrue(getDataCollectorBeanCalled[0]); + + verify(collectorBean).getThreadInfo(ids, true, true); + + verify(dao).saveSummary(anyString(), anyString(), any(ThreadSummary.class)); + + // once for each thread info + verify(dao, times(2)).saveThreadInfo(anyString(), anyString(), any(ThreadInfoData.class)); + + assertEquals(42, summaryCapture.getValue().currentLiveThreads()); + assertEquals("42", vmCapture.getValue()); + assertEquals("0xcafe", agentCapture.getValue()); + + assertEquals(42, summaryCapture.getValue().currentLiveThreads()); + assertEquals("42", vmCapture2.getAllValues().get(0)); + assertEquals("42", vmCapture2.getAllValues().get(1)); + + assertEquals("0xcafe", agentCapture2.getAllValues().get(0)); + assertEquals("0xcafe", agentCapture2.getAllValues().get(1)); + + List<ThreadInfoData> threadInfos = threadInfoCapture.getAllValues(); + assertEquals(2, threadInfos.size()); + + assertEquals("fluff1", threadInfos.get(0).getName()); + assertEquals("fluff2", threadInfos.get(1).getName()); + + verify(collectorBean, times(1)).getThreadCpuTime(1l); + verify(collectorBean, times(1)).getThreadCpuTime(2l); + } + + @Test + public void testSaveVmCaps() { + + final MXBeanConnector mockedConnector = mock(MXBeanConnector.class); + when(mockedConnector.isAttached()).thenReturn(true); + + ScheduledExecutorService executor = mock(ScheduledExecutorService.class); + + ArgumentCaptor<String> vmCapture = ArgumentCaptor.forClass(String.class); + ArgumentCaptor<String> agentCapture = ArgumentCaptor.forClass(String.class); + ArgumentCaptor<VMThreadCapabilities> capsCapture = ArgumentCaptor.forClass(VMThreadCapabilities.class); + + ThreadDao dao = mock(ThreadDao.class); + doNothing().when(dao).saveCapabilities(vmCapture.capture(), agentCapture.capture(), capsCapture.capture()); + + final ThreadMXBean collectorBean = mock(ThreadMXBean.class); + when(collectorBean.isThreadCpuTimeSupported()).thenReturn(true); + when(collectorBean.isThreadContentionMonitoringSupported()).thenReturn(true); + + final boolean [] getDataCollectorBeanCalled = new boolean[1]; + + Harvester harvester = new Harvester(dao, executor, "42", "0xcafe") { + { connector = mockedConnector; } + @Override + ThreadMXBean getDataCollectorBean(MXBeanConnection connection) + throws MalformedObjectNameException { + getDataCollectorBeanCalled[0] = true; + return collectorBean; + } + }; + + harvester.saveVmCaps(); + assertTrue(getDataCollectorBeanCalled[0]); + + verify(dao, times(1)).saveCapabilities(anyString(), anyString(), any(VMThreadCapabilities.class)); + assertEquals("42", vmCapture.getValue()); + assertEquals("0xcafe", agentCapture.getValue()); + + List<String> features = capsCapture.getValue().getSupportedFeaturesList(); + assertEquals(2, features.size()); + assertTrue(features.contains(ThreadDao.CPU_TIME)); + assertTrue(features.contains(ThreadDao.CONTENTION_MONITOR)); + assertFalse(features.contains(ThreadDao.THREAD_ALLOCATED_MEMORY)); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thread/harvester/src/test/java/com/redhat/thermostat/thread/harvester/ThreadHarvesterTest.java Fri Aug 31 11:26:14 2012 +0200 @@ -0,0 +1,166 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are 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.harvester; + +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 static org.mockito.Mockito.when; + +import java.util.List; +import java.util.concurrent.ScheduledExecutorService; + +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.common.command.Request; +import com.redhat.thermostat.thread.collector.HarvesterCommand; +import com.redhat.thermostat.thread.dao.ThreadDao; + +public class ThreadHarvesterTest { + + @Test + public void testStart() { + ScheduledExecutorService executor = mock(ScheduledExecutorService.class); + ThreadDao dao = mock(ThreadDao.class); + Request request = mock(Request.class); + + final boolean[] getHarvesterCalled = new boolean[1]; + final Harvester harverster = mock(Harvester.class); + + ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); + + when(request.getParameter(captor.capture())). + thenReturn(HarvesterCommand.START.name()). + thenReturn("42"). + thenReturn("0xcafe"); + + ThreadHarvester threadHarvester = new ThreadHarvester(executor, dao) { + @Override + Harvester getHarvester(String vmId, String agentId) { + + getHarvesterCalled[0] = true; + assertEquals("42", vmId); + assertEquals("0xcafe", agentId); + + return harverster; + } + }; + threadHarvester.receive(request); + + List<String> values = captor.getAllValues(); + assertEquals(3, values.size()); + + assertEquals(HarvesterCommand.class.getName(), values.get(0)); + assertEquals(HarvesterCommand.VM_ID.name(), values.get(1)); + assertEquals(HarvesterCommand.AGENT_ID.name(), values.get(2)); + + assertTrue(getHarvesterCalled[0]); + + verify(harverster).start(); + } + + @Test + public void testStop() { + ScheduledExecutorService executor = mock(ScheduledExecutorService.class); + ThreadDao dao = mock(ThreadDao.class); + Request request = mock(Request.class); + + final Harvester harverster = mock(Harvester.class); + + ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); + + when(request.getParameter(captor.capture())). + thenReturn(HarvesterCommand.STOP.name()). + thenReturn("42"); + + ThreadHarvester threadHarvester = new ThreadHarvester(executor, dao) { + { connectors.put("42", harverster); } + }; + threadHarvester.receive(request); + + List<String> values = captor.getAllValues(); + assertEquals(2, values.size()); + + assertEquals(HarvesterCommand.class.getName(), values.get(0)); + assertEquals(HarvesterCommand.VM_ID.name(), values.get(1)); + + verify(harverster).stop(); + } + + @Test + public void testSaveVmCaps() { + ScheduledExecutorService executor = mock(ScheduledExecutorService.class); + ThreadDao dao = mock(ThreadDao.class); + Request request = mock(Request.class); + + final boolean[] getHarvesterCalled = new boolean[1]; + final Harvester harverster = mock(Harvester.class); + + ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); + + when(request.getParameter(captor.capture())). + thenReturn(HarvesterCommand.VM_CAPS.name()). + thenReturn("42"). + thenReturn("0xcafe"); + + ThreadHarvester threadHarvester = new ThreadHarvester(executor, dao) { + @Override + Harvester getHarvester(String vmId, String agentId) { + + getHarvesterCalled[0] = true; + assertEquals("42", vmId); + assertEquals("0xcafe", agentId); + + return harverster; + } + }; + threadHarvester.receive(request); + + List<String> values = captor.getAllValues(); + assertEquals(3, values.size()); + + assertEquals(HarvesterCommand.class.getName(), values.get(0)); + assertEquals(HarvesterCommand.VM_ID.name(), values.get(1)); + assertEquals(HarvesterCommand.AGENT_ID.name(), values.get(2)); + + assertTrue(getHarvesterCalled[0]); + + verify(harverster).saveVmCaps(); + } +}
--- a/thread/pom.xml Fri Aug 31 11:22:52 2012 +0200 +++ b/thread/pom.xml Fri Aug 31 11:26:14 2012 +0200 @@ -60,10 +60,10 @@ <modules> <module>collector</module> + <module>harvester</module> <module>client-common</module> <module>client-swing</module> <module>client-controllers</module> </modules> - </project>