changeset 850:9f569536d421

Create VM Heap Analysis plugin This commit consolidates the heapdumper functionality of Thermostat into a self-contained plugin. Similar to previous commits, this moves the heapdumper client code to a top-level directory. The commit also splits the activator into a client-core activator which registers the VmInformationService and the client-swing activator which registers the various view providers. There are a number of other changes in this plugin. The agent component of the heapdumper is moved to an agent bundle in the plugin. The command related functionality is split away from the client-core bundle into a command bundle. The client-core code is then modified to not directly invoke command classes, but obtain the command via an OSGi service. This is done to not expose any heap command classes as API. Since there is a little more setup required to do this in a generic way, I have created a HeapDumper class. This class is responsible for setting up and running the dump-heap command. I have also added a test for this class. One other note is that since both command and client-core classes use PrintObjectUtils, I have duplicated this class in both bundles. This is done since this class is very small and it doesn't seem necessary to make it API. Reviewed-by: omajid, vanaltj, jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-December/004389.html
author Elliott Baron <ebaron@redhat.com>
date Wed, 12 Dec 2012 15:52:00 -0500
parents bdc4581c14d8
children ff0f033570c2
files agent/heapdumper/pom.xml agent/heapdumper/src/main/java/com/redhat/thermostat/agent/heapdumper/internal/Activator.java agent/heapdumper/src/main/java/com/redhat/thermostat/agent/heapdumper/internal/HeapDumpException.java agent/heapdumper/src/main/java/com/redhat/thermostat/agent/heapdumper/internal/HeapDumpReceiver.java agent/heapdumper/src/main/java/com/redhat/thermostat/agent/heapdumper/internal/JMXHeapDumper.java agent/heapdumper/src/main/java/com/redhat/thermostat/agent/heapdumper/internal/JMapHeapDumper.java agent/heapdumper/src/test/java/com/redhat/thermostat/agent/heapdumper/internal/ActivatorTest.java agent/heapdumper/src/test/java/com/redhat/thermostat/agent/heapdumper/internal/HeapDumpReceiverTest.java agent/pom.xml client/heapdumper/core/pom.xml client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapDumpController.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapDumpDetailsView.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapDumpDetailsViewProvider.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapDumperService.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapHistogramView.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapHistogramViewProvider.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapObjectUI.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapView.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapViewProvider.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/LocaleResources.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/ObjectDetailsView.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/ObjectDetailsViewProvider.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/ObjectRootsView.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/ObjectRootsViewProvider.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/chart/OverviewChart.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/DumpHeapCommand.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/FindObjectsCommand.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/FindRoot.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/FindRootCommand.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommand.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/HeapNotFoundException.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/HeapPath.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/ListHeapDumpsCommand.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/ObjectCommandHelper.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/ObjectInfoCommand.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/ObjectNotFoundException.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/SaveHeapDumpToFileCommand.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/ShowHeapHistogramCommand.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/internal/Activator.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/internal/HeapDumpDetailsController.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/internal/Histogram.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/internal/ObjectDetailsController.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/internal/ObjectRootsController.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/internal/PrintObjectUtils.java client/heapdumper/core/src/main/resources/META-INF/services/com.redhat.thermostat.common.cli.Command client/heapdumper/core/src/main/resources/com/redhat/thermostat/client/heap/strings.properties client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/HeapDumpControllerTest.java client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/HeapDumpDetailsControllerTest.java client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/LocaleResourcesTest.java client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/ObjectDetailsControllerTest.java client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/ObjectRootsControllerTest.java client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/DumpHeapCommandTest.java client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/FindObjectsCommandTest.java client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/FindRootCommandTest.java client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommandTest.java client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/ListHeapDumpsCommandTest.java client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/ObjectInfoCommandTest.java client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/SaveHeapDumpToFileCommandTest.java client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/ShowHeapHistogramCommandTest.java client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/internal/ActivatorTest.java client/heapdumper/pom.xml client/heapdumper/swing/pom.xml client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/Activator.java client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/HeapDetailsSwing.java client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/HeapPanel.java client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/HeapSwingView.java client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/HistogramPanel.java client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/LazyMutableTreeNode.java client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/ObjectDetailsPanel.java client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/ObjectRootsFrame.java client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/StatsPanel.java client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/SwingHeapDumpDetailsViewProvider.java client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/SwingHeapHistogramViewProvider.java client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/SwingHeapViewProvider.java client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/SwingObjectDetailsViewProvider.java client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/SwingObjectRootsViewProvider.java client/heapdumper/swing/src/test/java/com/redhat/thermostat/client/heap/swing/HeapDetailsSwingTest.java client/heapdumper/swing/src/test/java/com/redhat/thermostat/client/heap/swing/HeapSwingViewTest.java client/heapdumper/swing/src/test/java/com/redhat/thermostat/client/heap/swing/ObjectDetailsPanelTest.java client/heapdumper/swing/src/test/java/com/redhat/thermostat/client/heap/swing/ObjectRootsFrameTest.java client/heapdumper/swing/src/test/java/com/redhat/thermostat/client/heap/swing/ServicesAvailableActionTest.java client/pom.xml common/core/src/main/java/com/redhat/thermostat/common/dao/DAOFactory.java common/core/src/main/java/com/redhat/thermostat/common/dao/DAOFactoryImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/HeapDAO.java common/core/src/main/java/com/redhat/thermostat/common/dao/HeapDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/heap/HeapDump.java common/core/src/main/java/com/redhat/thermostat/common/heap/HistogramLoader.java common/core/src/main/java/com/redhat/thermostat/common/heap/HistogramRecord.java common/core/src/main/java/com/redhat/thermostat/common/heap/ObjectHistogram.java common/core/src/test/java/com/redhat/thermostat/common/dao/HeapDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/MongoDAOFactoryTest.java common/core/src/test/java/com/redhat/thermostat/common/heap/HeapDumpTest.java common/core/src/test/resources/heapdump.hprof.gz distribution/config/commands/agent.properties distribution/config/commands/dump-heap.properties distribution/config/commands/find-objects.properties distribution/config/commands/find-root.properties distribution/config/commands/gui.properties distribution/config/commands/list-heap-dumps.properties distribution/config/commands/object-info.properties distribution/config/commands/save-heap-dump-to-file.properties distribution/config/commands/show-heap-histogram.properties distribution/pom.xml eclipse/com.redhat.thermostat.eclipse.chart.common/META-INF/MANIFEST.MF pom.xml vm-heap-analysis/agent/pom.xml vm-heap-analysis/agent/src/main/java/com/redhat/thermostat/vm/heap/analysis/agent/internal/Activator.java vm-heap-analysis/agent/src/main/java/com/redhat/thermostat/vm/heap/analysis/agent/internal/HeapDumpException.java vm-heap-analysis/agent/src/main/java/com/redhat/thermostat/vm/heap/analysis/agent/internal/HeapDumpReceiver.java vm-heap-analysis/agent/src/main/java/com/redhat/thermostat/vm/heap/analysis/agent/internal/JMXHeapDumper.java vm-heap-analysis/agent/src/main/java/com/redhat/thermostat/vm/heap/analysis/agent/internal/JMapHeapDumper.java vm-heap-analysis/agent/src/test/java/com/redhat/thermostat/vm/heap/analysis/agent/internal/ActivatorTest.java vm-heap-analysis/agent/src/test/java/com/redhat/thermostat/vm/heap/analysis/agent/internal/HeapDumpReceiverTest.java vm-heap-analysis/client-core/pom.xml vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapDumpDetailsView.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapDumpDetailsViewProvider.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapDumperService.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapHistogramView.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapHistogramViewProvider.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapObjectUI.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapView.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapViewProvider.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/ObjectDetailsView.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/ObjectDetailsViewProvider.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/ObjectRootsView.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/ObjectRootsViewProvider.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/chart/OverviewChart.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/Activator.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpController.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpDetailsController.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumper.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/Histogram.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/ObjectDetailsController.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/ObjectRootsController.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/PrintObjectUtils.java vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/locale/LocaleResources.java vm-heap-analysis/client-core/src/main/resources/com/redhat/thermostat/vm/heap/analysis/client/locale/strings.properties vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/ActivatorTest.java vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpControllerTest.java vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpDetailsControllerTest.java vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumperTest.java vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/ObjectDetailsControllerTest.java vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/ObjectRootsControllerTest.java vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/locale/LocaleResourcesTest.java vm-heap-analysis/client-swing/pom.xml vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/Activator.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapDetailsSwing.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapPanel.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapSwingView.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HistogramPanel.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/LazyMutableTreeNode.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectDetailsPanel.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectRootsFrame.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/StatsPanel.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/SwingHeapDumpDetailsViewProvider.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/SwingHeapHistogramViewProvider.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/SwingHeapViewProvider.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/SwingObjectDetailsViewProvider.java vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/SwingObjectRootsViewProvider.java vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ActivatorTest.java vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapDetailsSwingTest.java vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapSwingViewTest.java vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectDetailsPanelTest.java vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectRootsFrameTest.java vm-heap-analysis/command/pom.xml vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/FindRoot.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/HeapPath.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/Activator.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/DumpHeapCommand.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/DumpHeapHelper.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/FindObjectsCommand.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/FindRootCommand.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/HeapNotFoundException.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ListHeapDumpsCommand.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ObjectCommandHelper.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ObjectInfoCommand.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ObjectNotFoundException.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/PrintObjectUtils.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/SaveHeapDumpToFileCommand.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ShowHeapHistogramCommand.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/locale/LocaleResources.java vm-heap-analysis/command/src/main/resources/META-INF/services/com.redhat.thermostat.common.cli.Command vm-heap-analysis/command/src/main/resources/com/redhat/thermostat/vm/heap/analysis/command/locale/strings.properties vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ActivatorTest.java vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/DumpHeapCommandTest.java vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/DumpHeapHelperTest.java vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/FindObjectsCommandTest.java vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/FindRootCommandTest.java vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ListHeapDumpsCommandTest.java vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ObjectInfoCommandTest.java vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/SaveHeapDumpToFileCommandTest.java vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ShowHeapHistogramCommandTest.java vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/locale/LocaleResourcesTest.java vm-heap-analysis/common/pom.xml vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/HeapDAO.java vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/HeapDump.java vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/HistogramLoader.java vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/HistogramRecord.java vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/ObjectHistogram.java vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/Activator.java vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImpl.java vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/HeapDumpTest.java vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOTest.java vm-heap-analysis/common/src/test/resources/heapdump.hprof.gz vm-heap-analysis/pom.xml
diffstat 206 files changed, 12024 insertions(+), 11080 deletions(-) [+]
line wrap: on
line diff
--- a/agent/heapdumper/pom.xml	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-<?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-agent</artifactId>
-    <version>0.5.0-SNAPSHOT</version>
-  </parent>
-
-  <artifactId>thermostat-agent-heapdumper</artifactId>
-  <packaging>bundle</packaging>
-
-  <name>Thermostat Heapdumper Agent Module</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>org.powermock</groupId>
-      <artifactId>powermock-api-mockito</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.powermock</groupId>
-      <artifactId>powermock-module-junit4</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.osgi</groupId>
-      <artifactId>org.osgi.core</artifactId>
-    </dependency>
-
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-agent-command</artifactId>
-      <version>${project.version}</version>
-    </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.agent.heapdumper.internal.Activator</Bundle-Activator>
-            <Bundle-SymbolicName>com.redhat.thermostat.agent.heapdumper</Bundle-SymbolicName>
-            <Export-Package>
-              com.redhat.thermostat.agent.heapdumper
-            </Export-Package>
-            <Private-Package>
-              com.redhat.thermostat.agent.heapdumper.internal
-            </Private-Package>
-            <!-- Do not autogenerate uses clauses in Manifests -->
-            <_nouses>true</_nouses>
-          </instructions>
-        </configuration>
-      </plugin>
-    </plugins>
-  </build>
-
-</project>
-
--- a/agent/heapdumper/src/main/java/com/redhat/thermostat/agent/heapdumper/internal/Activator.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +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.agent.heapdumper.internal;
-
-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.common.dao.HeapDAO;
-
-public class Activator implements BundleActivator {
-
-    private ReceiverRegistry receivers;
-
-    private HeapDumpReceiver receiver = null;
-
-    private ServiceTracker heapDumpCommandReceiverTracker;
-
-    @Override
-    public void start(BundleContext context) {
-        receivers = new ReceiverRegistry(context);
-
-        heapDumpCommandReceiverTracker = new ServiceTracker(context, HeapDAO.class, null) {
-            @Override
-            public Object addingService(ServiceReference reference) {
-                HeapDAO service = (HeapDAO) super.addingService(reference);
-                receiver = new HeapDumpReceiver(service);
-                receivers.registerReceiver(receiver);
-                return service;
-            }
-
-            @Override
-            public void removedService(ServiceReference reference, Object service) {
-                receivers.unregisterReceivers();
-                super.removedService(reference, service);
-            }
-        };
-        heapDumpCommandReceiverTracker.open();
-
-    }
-
-    @Override
-    public void stop(BundleContext context) {
-        heapDumpCommandReceiverTracker.close();
-
-        receivers.unregisterReceivers();
-    }
-
-}
--- a/agent/heapdumper/src/main/java/com/redhat/thermostat/agent/heapdumper/internal/HeapDumpException.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +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.agent.heapdumper.internal;
-
-@SuppressWarnings("serial")
-public class HeapDumpException extends Exception {
-
-    public HeapDumpException() {
-        super();
-    }
-
-    public HeapDumpException(String message) {
-        super(message);
-    }
-
-    public HeapDumpException(Throwable cause) {
-        super(cause);
-    }
-
-    public HeapDumpException(String message, Throwable cause) {
-        super(message, cause);
-    }
-
-}
--- a/agent/heapdumper/src/main/java/com/redhat/thermostat/agent/heapdumper/internal/HeapDumpReceiver.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,126 +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.agent.heapdumper.internal;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-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.common.dao.HeapDAO;
-import com.redhat.thermostat.common.heap.HistogramLoader;
-import com.redhat.thermostat.common.heap.ObjectHistogram;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.model.HeapInfo;
-
-public class HeapDumpReceiver implements RequestReceiver {
-
-    private static final Logger log = LoggingUtils.getLogger(HeapDumpReceiver.class);
-
-    private final HeapDAO heapDao;
-
-    private final JMXHeapDumper jmxHeapDumper;
-    private final JMapHeapDumper jmapHeapDumper;
-
-    private final HistogramLoader histogramLoader;
-
-    public HeapDumpReceiver(HeapDAO heapDao) {
-        this(heapDao, new JMXHeapDumper(), new JMapHeapDumper(), new HistogramLoader());
-    }
-
-    HeapDumpReceiver(HeapDAO heapDao, JMXHeapDumper jmxHeapDumper, JMapHeapDumper jmapHeapDumper, HistogramLoader histogramLoader) {
-        this.heapDao = heapDao;
-        this.jmxHeapDumper = jmxHeapDumper;
-        this.jmapHeapDumper = jmapHeapDumper;
-        this.histogramLoader = histogramLoader;
-    }
-
-    @Override
-    public Response receive(Request request) {
-        String vmId = request.getParameter("vmId");
-        try {
-            File heapDumpFile = dumpHeap(vmId);
-            ObjectHistogram histogram = loadHistogram(heapDumpFile.getAbsolutePath());
-            saveHeapDumpInfo(vmId, heapDumpFile, histogram);
-            
-        } catch (IOException e) {
-            log.log(Level.SEVERE, "Unexpected IO problem while writing heap dump", e);
-            return new Response(ResponseType.ERROR);
-        } catch (HeapDumpException e) {
-            log.log(Level.SEVERE, "Unexpected problem while writing heap dump", e);
-            return new Response(ResponseType.ERROR);
-        }
-        return new Response(ResponseType.OK);
-    }
-
-    private File dumpHeap(String vmId) throws IOException, HeapDumpException {
-        File tempFile = Files.createTempFile("thermostat-", "-heapdump").toFile();
-        String tempFileName = tempFile.getAbsolutePath();
-        tempFile.delete(); // Need to delete before dumping heap, jmap does not override existing file and stop with an error.
-        dumpHeapUsingJMX(vmId, tempFileName);
-        return tempFile;
-    }
-
-    private void dumpHeapUsingJMX(String vmId, String filename) throws HeapDumpException {
-
-        try {
-            jmxHeapDumper.dumpHeap(vmId, filename);
-        } catch (HeapDumpException e) {
-            log.log(Level.WARNING, "Heap dump using JMX failed, trying jmap", e);
-            dumpHeapUsingJMap(vmId, filename);
-        }
-    }
-
-    private void dumpHeapUsingJMap(String vmId, String filename) throws HeapDumpException {
-        jmapHeapDumper.dumpHeap(vmId, filename);
-    }
-
-    private ObjectHistogram loadHistogram(String heapDumpFilename) throws IOException {
-        return histogramLoader.load(heapDumpFilename);
-    }
-
-    private void saveHeapDumpInfo(String vmId, File tempFile, ObjectHistogram histogram) throws IOException {
-        HeapInfo heapInfo = new HeapInfo(Integer.parseInt(vmId), System.currentTimeMillis());
-        heapDao.putHeapInfo(heapInfo, tempFile, histogram);
-    }
-
-}
--- a/agent/heapdumper/src/main/java/com/redhat/thermostat/agent/heapdumper/internal/JMXHeapDumper.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +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.agent.heapdumper.internal;
-
-import java.io.File;
-import java.util.Properties;
-
-import javax.management.MBeanServerConnection;
-import javax.management.ObjectName;
-import javax.management.remote.JMXConnector;
-import javax.management.remote.JMXConnectorFactory;
-import javax.management.remote.JMXServiceURL;
-
-import com.sun.tools.attach.VirtualMachine;
-
-class JMXHeapDumper {
-
-    private static final String CONNECTOR_ADDRESS_PROPERTY = "com.sun.management.jmxremote.localConnectorAddress";
-
-    void dumpHeap(String vmId, String filename) throws HeapDumpException {
-        try {
-            doHeapDump(vmId, filename);
-        } catch (Exception ex) {
-            throw new HeapDumpException(ex);
-        }
-    }
-
-    private void doHeapDump(String vmId, String filename) throws Exception {
-
-        VirtualMachine vm = VirtualMachine.attach(vmId);
-        String connectorAddress = getConnectorAddress(vm);
-        JMXServiceURL url = new JMXServiceURL(connectorAddress);
-
-        try (JMXConnector conn = JMXConnectorFactory.connect(url)) {
-            MBeanServerConnection mbsc = conn.getMBeanServerConnection();
-            mbsc.invoke(new ObjectName("com.sun.management:type=HotSpotDiagnostic"),
-                        "dumpHeap",
-                        new Object[] { filename, Boolean.TRUE },
-                        new String[] { String.class.getName(), boolean.class.getName() });
-        }
-    }
-
-    private String getConnectorAddress(VirtualMachine vm) throws Exception {
-
-        Properties props = vm.getAgentProperties();
-        String 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);
-        }
-        return connectorAddress;
-    }
-}
--- a/agent/heapdumper/src/main/java/com/redhat/thermostat/agent/heapdumper/internal/JMapHeapDumper.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +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.agent.heapdumper.internal;
-
-import java.io.IOException;
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.common.utils.LoggingUtils;
-
-class JMapHeapDumper {
-
-    private static final Logger log = LoggingUtils.getLogger(JMapHeapDumper.class);
-
-    void dumpHeap(String vmId, String filename) throws HeapDumpException {
-        try {
-            Process proc = Runtime.getRuntime().exec(
-                    new String[] { "jmap", "-dump:format=b,file=" + filename, vmId });
-            proc.waitFor();
-            log.info("Heap dump written to: " + filename);
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-        } catch (IOException ex) {
-            throw new HeapDumpException(ex);
-        }
-    }
-}
--- a/agent/heapdumper/src/test/java/com/redhat/thermostat/agent/heapdumper/internal/ActivatorTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +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.agent.heapdumper.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import static org.mockito.Mockito.mock;
-
-import org.junit.Test;
-import org.osgi.framework.ServiceRegistration;
-
-import com.redhat.thermostat.agent.command.RequestReceiver;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.test.StubBundleContext;
-
-public class ActivatorTest {
-
-    @Test
-    public void testStartStopWithoutDependencies() {
-        StubBundleContext ctx = new StubBundleContext();
-
-        Activator activator = new Activator();
-
-        activator.start(ctx);
-
-        assertEquals(0, ctx.getAllServices().size());
-
-        activator.stop(ctx);
-
-        assertEquals(0, ctx.getAllServices().size());
-        assertEquals(0, ctx.getServiceListeners().size());
-    }
-
-    @Test
-    public void testStartStopWithDependency() throws Exception {
-        StubBundleContext ctx = new StubBundleContext();
-
-        HeapDAO heapDao = mock(HeapDAO.class);
-        ServiceRegistration registration = ctx.registerService(HeapDAO.class, heapDao, null);
-
-        Activator activator = new Activator();
-
-        activator.start(ctx);
-
-        assertTrue(ctx.isServiceRegistered(RequestReceiver.class.getName(), HeapDumpReceiver.class));
-
-        assertEquals(1, ctx.getServiceListeners().size());
-
-        activator.stop(ctx);
-
-        assertFalse(ctx.isServiceRegistered(RequestReceiver.class.getName(), HeapDumpReceiver.class));
-
-        assertEquals(0, ctx.getServiceListeners().size());
-
-        assertEquals(0, ctx.getExportedServiceCount(registration));
-    }
-
-}
--- a/agent/heapdumper/src/test/java/com/redhat/thermostat/agent/heapdumper/internal/HeapDumpReceiverTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +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.agent.heapdumper.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.same;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.io.File;
-import java.io.IOException;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-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.common.dao.HeapDAO;
-import com.redhat.thermostat.common.heap.HistogramLoader;
-import com.redhat.thermostat.common.heap.ObjectHistogram;
-import com.redhat.thermostat.storage.model.HeapInfo;
-
-public class HeapDumpReceiverTest {
-
-    private HeapDAO heapDAO;
-    private Request request;
-    private JMXHeapDumper jmxDumper;
-    private HistogramLoader histogramLoader;
-
-    private HeapDumpReceiver receiver;
-    private JMapHeapDumper jmapDumper;
-
-    @Before
-    public void setUp() {
-        heapDAO = mock(HeapDAO.class);
-
-        request = mock(Request.class);
-        when(request.getParameter("vmId")).thenReturn("123");
-        jmxDumper = mock(JMXHeapDumper.class);
-        jmapDumper = mock(JMapHeapDumper.class);
-        histogramLoader = mock(HistogramLoader.class);
-        receiver = new HeapDumpReceiver(heapDAO, jmxDumper, jmapDumper, histogramLoader);
-    }
-
-    @After
-    public void tearDown() {
-        histogramLoader = null;
-        jmapDumper = null;
-        jmxDumper = null;
-        request = null;
-        heapDAO = null;
-    }
-
-    @Test
-    public void testJMXHeapDump() throws Exception {
-
-        ObjectHistogram expectedHistogramData = mock(ObjectHistogram.class);
-        when(histogramLoader.load(anyString())).thenReturn(expectedHistogramData);
-        
-        Response response = receiver.receive(request);
-
-        assertEquals(ResponseType.OK, response.getType());
-        ArgumentCaptor<String> filename = ArgumentCaptor.forClass(String.class);
-        verify(jmxDumper).dumpHeap(eq("123"), filename.capture());
-        verify(histogramLoader).load(filename.getValue());
-        ArgumentCaptor<HeapInfo> heapInfo = ArgumentCaptor.forClass(HeapInfo.class);
-        verify(heapDAO).putHeapInfo(heapInfo.capture(), eq(new File(filename.getValue())), same(expectedHistogramData));
-        assertEquals(123, heapInfo.getValue().getVmId());
-    }
-
-    @Test
-    public void verifyFallbackWhenJMXFails() throws HeapDumpException {
-
-        doThrow(new HeapDumpException()).when(jmxDumper).dumpHeap(anyString(), anyString());
-
-        Response response = receiver.receive(request);
-
-        assertEquals(ResponseType.OK, response.getType());
-        verify(jmxDumper).dumpHeap(eq("123"), anyString());
-        
-    }
-
-    @Test
-    public void verifyResponseTypeWhenAllFails() throws HeapDumpException {
-        doThrow(new HeapDumpException()).when(jmxDumper).dumpHeap(anyString(), anyString());
-        doThrow(new HeapDumpException()).when(jmapDumper).dumpHeap(anyString(), anyString());
-        Response response = receiver.receive(request);
-
-        assertEquals(ResponseType.ERROR, response.getType());
-        
-    }
-
-    @Test
-    public void verifyResponseTypeWhenIOFails() throws HeapDumpException, IOException {
-        doThrow(new IOException()).when(histogramLoader).load(anyString());
-
-        Response response = receiver.receive(request);
-
-        assertEquals(ResponseType.ERROR, response.getType());
-        
-    }
-}
--- a/agent/pom.xml	Wed Dec 12 16:42:37 2012 +0100
+++ b/agent/pom.xml	Wed Dec 12 15:52:00 2012 -0500
@@ -62,7 +62,6 @@
     <module>cli</module>
     <module>core</module>
     <module>command</module>
-    <module>heapdumper</module>
   </modules>
 
 </project>
--- a/client/heapdumper/core/pom.xml	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,146 +0,0 @@
-<?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>
-    <artifactId>thermostat-client-heapdumper</artifactId>
-    <groupId>com.redhat.thermostat</groupId>
-    <version>0.5.0-SNAPSHOT</version>
-  </parent>
-  <artifactId>thermostat-client-heapdumper-core</artifactId>
-  <packaging>bundle</packaging>
-  <name>Thermostat Client Heap Dumper Core plugin</name>
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <configuration>
-          <instructions>
-            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
-            <Bundle-SymbolicName>com.redhat.thermostat.client.heapdumper.core</Bundle-SymbolicName>
-            <Export-Package>
-               com.redhat.thermostat.client.heap,
-               com.redhat.thermostat.client.heap.chart
-            </Export-Package>
-            <Private-Package>
-               com.redhat.thermostat.client.heap.internal,
-               com.redhat.thermostat.client.heap.cli
-            </Private-Package>
-            <!-- Do not autogenerate uses clauses in Manifests -->
-            <_nouses>true</_nouses>
-          </instructions>
-        </configuration>
-      </plugin>
-    </plugins>
-  </build>
-  <dependencies>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.mockito</groupId>
-      <artifactId>mockito-core</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.powermock</groupId>
-      <artifactId>powermock-api-mockito</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.powermock</groupId>
-      <artifactId>powermock-module-junit4</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.osgi</groupId>
-      <artifactId>org.osgi.core</artifactId>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.osgi</groupId>
-      <artifactId>org.osgi.compendium</artifactId>
-      <scope>provided</scope>
-    </dependency>
-    
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-common-core</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-client-core</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-tools</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-client-command</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-agent-heapdumper</artifactId>
-      <version>${project.version}</version>
-      <scope>test</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>org.jfree</groupId>
-      <artifactId>jfreechart</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>com.sun</groupId>
-      <artifactId>tools</artifactId>
-      <scope>system</scope>
-      <systemPath>${java.home}/../lib/tools.jar</systemPath>
-    </dependency>
-    
-  </dependencies>
-</project>
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapDumpController.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,278 +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.client.heap;
-
-import java.text.DecimalFormat;
-import java.text.NumberFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import com.redhat.thermostat.client.core.controllers.VmInformationServiceController;
-import com.redhat.thermostat.client.core.views.BasicView.Action;
-import com.redhat.thermostat.client.core.views.UIComponent;
-import com.redhat.thermostat.client.heap.HeapView.HeapDumperAction;
-import com.redhat.thermostat.client.heap.chart.OverviewChart;
-import com.redhat.thermostat.client.heap.cli.HeapDumperCommand;
-import com.redhat.thermostat.client.heap.internal.HeapDumpDetailsController;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.ApplicationService;
-import com.redhat.thermostat.common.NotImplementedException;
-import com.redhat.thermostat.common.Timer;
-import com.redhat.thermostat.common.Timer.SchedulingType;
-import com.redhat.thermostat.common.dao.AgentInfoDAO;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
-import com.redhat.thermostat.storage.model.HeapInfo;
-import com.redhat.thermostat.storage.model.VmMemoryStat;
-import com.redhat.thermostat.storage.model.VmMemoryStat.Generation;
-import com.redhat.thermostat.storage.model.VmMemoryStat.Space;
-
-public class HeapDumpController implements VmInformationServiceController {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private final VmMemoryStatDAO vmDao;
-    private final VmRef ref;
-    
-    private final HeapDAO heapDAO;
-        
-    private HeapView view;
-    private final Timer timer;
-    
-    private OverviewChart model;
-    private ApplicationService appService;
-    private HeapDumpDetailsViewProvider detailsViewProvider;
-    private HeapHistogramViewProvider histogramViewProvider;
-    private ObjectDetailsViewProvider objectDetailsViewProvider;
-    private ObjectRootsViewProvider objectRootsViewProvider;
-
-    public HeapDumpController(final AgentInfoDAO agentInfoDao, final VmMemoryStatDAO vmMemoryStatDao, final HeapDAO heapDao, final VmRef ref, final ApplicationService appService, HeapViewProvider viewProvider, HeapDumpDetailsViewProvider detailsViewProvider, HeapHistogramViewProvider histogramProvider, ObjectDetailsViewProvider objectDetailsProvider, ObjectRootsViewProvider objectRootsProvider) {
-        this(agentInfoDao, vmMemoryStatDao, heapDao, ref, appService, new HeapDumperCommand(), viewProvider, detailsViewProvider, histogramProvider, objectDetailsProvider, objectRootsProvider);
-    }
-
-    HeapDumpController(final AgentInfoDAO agentInfoDao, final VmMemoryStatDAO vmMemoryStatDao, final HeapDAO heapDao, final VmRef ref, final ApplicationService appService, final HeapDumperCommand command, HeapViewProvider viewProvider, HeapDumpDetailsViewProvider detailsViewProvider, HeapHistogramViewProvider histogramProvider, ObjectDetailsViewProvider objectDetailsProvider, ObjectRootsViewProvider objectRootsProvider) {
-        
-        this.objectDetailsViewProvider = objectDetailsProvider;
-        this.objectRootsViewProvider = objectRootsProvider;
-        this.histogramViewProvider = histogramProvider;
-        this.detailsViewProvider = detailsViewProvider;
-        this.appService = appService;
-        this.ref = ref;
-        this.vmDao = vmMemoryStatDao;
-        this.heapDAO = heapDao;
-        
-        model = new OverviewChart(
-                    translator.localize(LocaleResources.HEAP_CHART_TITLE),
-                    translator.localize(LocaleResources.HEAP_CHART_TIME_AXIS),
-                    translator.localize(LocaleResources.HEAP_CHART_HEAP_AXIS),
-                    translator.localize(LocaleResources.HEAP_CHART_CAPACITY),
-                    translator.localize(LocaleResources.HEAP_CHART_USED));
-        
-        timer = appService.getTimerFactory().createTimer();
-        timer.setAction(new HeapOverviewDataCollector());
-        
-        timer.setInitialDelay(0);
-        timer.setDelay(1000);
-        model.setRange(3600);
-        timer.setTimeUnit(TimeUnit.MILLISECONDS);
-        timer.setSchedulingType(SchedulingType.FIXED_RATE);
-        
-        view = viewProvider.createView();
-        view.setModel(model);
-        
-        HeapDump dump = null;
-        view.clearHeapDumpList();
-        Collection<HeapInfo> infos = heapDAO.getAllHeapInfo(ref);
-        for (HeapInfo info : infos) {
-            dump = new HeapDump(info, heapDAO);
-            view.addHeapDump(dump);
-        }
-        
-        // check if we were reading some of the dumps
-        dump = (HeapDump) appService.getApplicationCache().getAttribute(ref);
-        if (dump != null && infos.contains(dump.getInfo())) {
-            showHeapDumpDetails(dump);
-        }
-        
-        view.addActionListener(new ActionListener<Action>() {            
-            @Override
-            public void actionPerformed(ActionEvent<Action> actionEvent) {
-                switch (actionEvent.getActionId()) {
-                case HIDDEN:
-                    timer.stop();
-                    break;
-                
-                case VISIBLE:                    
-                    timer.start();
-                    break;
-
-                default:
-                    throw new NotImplementedException("unknown event: " + actionEvent.getActionId());
-                }
-            }
-        });
-
-        view.addDumperListener(new ActionListener<HeapView.HeapDumperAction>() {
-            @Override
-            public void actionPerformed(ActionEvent<HeapDumperAction> actionEvent) {
-                HeapDump dump = null;
-                switch (actionEvent.getActionId()) {
-                case DUMP_REQUESTED:
-                    command.execute(agentInfoDao, ref, new Runnable() {
-                        public void run() {
-                            view.notifyHeapDumpComplete();
-                        }
-                    }, new Runnable() {
-                        @Override
-                        public void run() {
-                            view.displayWarning(translator.localize(
-                                    LocaleResources.HEAP_DUMP_ERROR,
-                                    ref.getAgent().getAgentId(),
-                                    ref.getIdString()));
-                        }
-                    });
-                    
-                    break;
-                
-                case ANALYSE:
-                    dump = (HeapDump) actionEvent.getPayload();
-                    analyseDump(dump);
-                    break;
-                }
-            }
-        });
-    }
-
-    
-    private void analyseDump(final HeapDump dump) {
-        appService.getApplicationExecutor().execute(new Runnable() {
-            
-            @Override
-            public void run() {
-                showHeapDumpDetails(dump);
-                appService.getApplicationCache().addAttribute(ref, dump);
-            }
-        });
-    }
-
-    private void showHeapDumpDetails(HeapDump dump) {
-        HeapDumpDetailsController controller = new HeapDumpDetailsController(appService, detailsViewProvider, histogramViewProvider, objectDetailsViewProvider, objectRootsViewProvider);
-        controller.setDump(dump);
-        view.setChildView(controller.getView());
-        view.openDumpView();
-    }
-
-    @Override
-    public UIComponent getView() {
-        return (UIComponent) view;
-    }
-
-    @Override
-    public String getLocalizedName() {
-        return translator.localize(LocaleResources.HEAP_SECTION_TITLE);
-    }
-
-    class HeapOverviewDataCollector implements Runnable {
-
-        private long desiredUpdateTimeStamp = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1);
-
-        @Override
-        public void run() {
-            checkForHeapDumps();
-            updateMemoryChartAndDisplay();
-        }
-
-        private void checkForHeapDumps() {
-            Collection<HeapInfo> heapInfos = heapDAO.getAllHeapInfo(ref);
-            List<HeapDump> heapDumps = new ArrayList<HeapDump>(heapInfos.size());
-            for (HeapInfo heapInfo : heapInfos) {
-                heapDumps.add(new HeapDump(heapInfo, heapDAO));
-            }
-            view.updateHeapDumpList(heapDumps);
-        }
-
-        private void updateMemoryChartAndDisplay() {
-            List<VmMemoryStat> vmInfo = null;
-            vmInfo = vmDao.getLatestVmMemoryStats(ref, desiredUpdateTimeStamp);
-
-            for (VmMemoryStat memoryStats: vmInfo) {
-                long used = 0l;
-                long capacity = 0l;
-                long max = 0l;
-                Generation[] generations = memoryStats.getGenerations();
-                for (Generation generation : generations) {
-                    
-                    // non heap
-                    if (generation.getName().equals("perm")) {
-                        continue;
-                    }
-                    
-                    Space[] spaces = generation.getSpaces();
-                    for (Space space: spaces) {
-                        used += space.getUsed();
-                        capacity += space.getCapacity();
-                        
-                        // TODO
-                        max =+ space.getMaxCapacity();
-                    }
-                }
-                model.addData(memoryStats.getTimeStamp(), used, capacity);
-                
-                NumberFormat formatter = DecimalFormat.getInstance();
-
-                double res = Scale.convertTo(Scale.B, used);
-                String _used = formatter.format(res) + " " + Scale.B;
-                
-                res = Scale.convertTo(Scale.B, capacity);
-                String _capacity= formatter.format(capacity) + " " + Scale.B;
-                
-                view.updateUsedAndCapacity(_used, _capacity);
-                desiredUpdateTimeStamp = Math.max(desiredUpdateTimeStamp, memoryStats.getTimeStamp());
-            }
-
-            model.notifyListenersOfModelChange();
-        }
-
-    }
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapDumpDetailsView.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +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.client.heap;
-
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.core.views.UIComponent;
-
-public abstract class HeapDumpDetailsView extends BasicView implements UIComponent {
-
-    public abstract void addSubView(String title, HeapHistogramView child);
-    public abstract void addSubView(String title, ObjectDetailsView child);
-    public abstract void removeSubView(String title);
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapDumpDetailsViewProvider.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +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.client.heap;
-
-import com.redhat.thermostat.client.core.views.ViewProvider;
-
-public interface HeapDumpDetailsViewProvider extends ViewProvider {
-
-    @Override
-    public HeapDumpDetailsView createView();
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapDumperService.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +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.client.heap;
-
-import com.redhat.thermostat.client.core.VmFilter;
-import com.redhat.thermostat.client.core.VmInformationService;
-import com.redhat.thermostat.client.core.controllers.VmInformationServiceController;
-import com.redhat.thermostat.client.osgi.service.AlwaysMatchFilter;
-import com.redhat.thermostat.common.ApplicationService;
-import com.redhat.thermostat.common.dao.AgentInfoDAO;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-
-public class HeapDumperService implements VmInformationService {
-    
-    private static final int PRIORITY = PRIORITY_MEMORY_GROUP + 60;
-    private ApplicationService appService;
-    private AgentInfoDAO agentInfoDao;
-    private VmMemoryStatDAO vmMemoryStatDao;
-    private HeapDAO heapDao;
-
-    private VmFilter filter = new AlwaysMatchFilter();
-    private HeapDumpDetailsViewProvider detailsViewProvider;
-    private HeapHistogramViewProvider histogramViewProvider;
-    private HeapViewProvider viewProvider;
-    private ObjectDetailsViewProvider objectDetailsViewProvider;
-    private ObjectRootsViewProvider objectRootsViewProvider;
-
-    public HeapDumperService(ApplicationService appService, AgentInfoDAO agentInfoDao, VmMemoryStatDAO vmMemoryStatDao, HeapDAO heapDao, HeapDumpDetailsViewProvider detailsViewProvider, HeapViewProvider viewProvider, HeapHistogramViewProvider histogramViewProvider, ObjectDetailsViewProvider objectDetailsViewProvider, ObjectRootsViewProvider objectRootsViewProvider) {
-        this.agentInfoDao = agentInfoDao;
-        this.vmMemoryStatDao = vmMemoryStatDao;
-        this.heapDao = heapDao;
-        this.appService = appService;
-        this.viewProvider = viewProvider;
-        this.detailsViewProvider = detailsViewProvider;
-        this.histogramViewProvider = histogramViewProvider;
-        this.objectDetailsViewProvider = objectDetailsViewProvider;
-        this.objectRootsViewProvider = objectRootsViewProvider;
-    }
-
-    @Override
-    public VmInformationServiceController getInformationServiceController(VmRef ref) {
-        return new HeapDumpController(agentInfoDao, vmMemoryStatDao, heapDao, ref, appService, viewProvider, detailsViewProvider, histogramViewProvider, objectDetailsViewProvider, objectRootsViewProvider);
-    }
-
-    @Override
-    public VmFilter getFilter() {
-        return filter;
-    }
-
-    @Override
-    public int getPriority() {
-        return PRIORITY;
-    }
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapHistogramView.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +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.client.heap;
-
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.core.views.UIComponent;
-import com.redhat.thermostat.common.heap.ObjectHistogram;
-
-public abstract class HeapHistogramView extends BasicView implements UIComponent {
-
-    public abstract void display(ObjectHistogram histogram);
-
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapHistogramViewProvider.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +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.client.heap;
-
-import com.redhat.thermostat.client.core.views.ViewProvider;
-
-public interface HeapHistogramViewProvider extends ViewProvider {
-
-    @Override
-    public HeapHistogramView createView();
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapObjectUI.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +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.client.heap;
-
-public class HeapObjectUI {
-
-    public String objectId;
-    public String text;
-
-    public HeapObjectUI(String objectId, String text) {
-        this.objectId = objectId;
-        this.text = text;
-    }
-
-    @Override
-    public String toString() {
-        return text;
-    }
-}
\ No newline at end of file
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapView.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +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.client.heap;
-
-import java.util.List;
-
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.core.views.UIComponent;
-import com.redhat.thermostat.client.heap.chart.OverviewChart;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.ActionNotifier;
-import com.redhat.thermostat.common.heap.HeapDump;
-
-public abstract class HeapView extends BasicView implements UIComponent {
-    
-    public enum HeapDumperAction {
-        DUMP_REQUESTED,
-        ANALYSE,
-        REQUEST_ABORTED
-    }
-   
-    protected final ActionNotifier<HeapDumperAction> heapDumperNotifier;
-    protected HeapView() {
-        heapDumperNotifier = new ActionNotifier<HeapDumperAction>(this);
-    }
-    
-    public void addDumperListener(ActionListener<HeapDumperAction> listener) {
-        heapDumperNotifier.addActionListener(listener);
-    }
-    
-    public void removeDumperListener(ActionListener<HeapDumperAction> listener) {
-        heapDumperNotifier.removeActionListener(listener);
-    }
-
-    abstract public void updateUsedAndCapacity(String used, String capacity);
-    /** View updates automatically based on the model */
-    abstract public void setModel(OverviewChart model);
-    abstract public void addHeapDump(HeapDump dump);
-    abstract public void clearHeapDumpList();
-    
-    abstract public void openDumpView();
-    abstract public void setChildView(BasicView childView);
-    public abstract void notifyHeapDumpComplete();
-
-    public abstract void updateHeapDumpList(List<HeapDump> heapDumps);
-
-    public abstract void displayWarning(String string);
-
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapViewProvider.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +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.client.heap;
-
-import com.redhat.thermostat.client.core.views.ViewProvider;
-
-public interface HeapViewProvider extends ViewProvider {
-
-    @Override
-    public HeapView createView();
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/LocaleResources.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +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.client.heap;
-
-import com.redhat.thermostat.common.locale.Translate;
-
-public enum LocaleResources {
-
-    MISSING_INFO,
-    HOST_SERVICE_UNAVAILABLE,
-    VM_SERVICE_UNAVAILABLE,
-    HEAP_SERVICE_UNAVAILABLE,
-
-    HEADER_TIMESTAMP,
-    HEADER_HOST_ID,
-    HEADER_VM_ID,
-    HEADER_HEAP_ID,
-    HEADER_OBJECT_ID,
-    HEADER_OBJECT_TYPE,
-
-    FILE_REQUIRED,
-    INVALID_LIMIT,
-    HEAP_ID_NOT_FOUND,
-    HEAP_ID_REQUIRED,
-    SEARCH_TERM_REQUIRED,
-    HEAP_DUMP_ERROR,
-
-    COMMAND_HEAP_DUMP_DONE,
-
-    COMMAND_FIND_ROOT_NO_ROOT_FOUND,
-
-    COMMAND_OBJECT_INFO_OBJECT_ID,
-    COMMAND_OBJECT_INFO_TYPE,
-    COMMAND_OBJECT_INFO_SIZE,
-    COMMAND_OBJECT_INFO_HEAP_ALLOCATED,
-    COMMAND_OBJECT_INFO_REFERENCES,
-    COMMAND_OBJECT_INFO_REFERRERS,
-
-    COMMAND_SAVE_HEAP_DUMP_SAVED_TO_FILE,
-    COMMAND_SAVE_HEAP_DUMP_ERROR_SAVING,
-    COMMAND_SAVE_HEAP_DUMP_ERROR_CLOSING_STREAM,
-
-    HEAP_SECTION_TITLE,
-    HEAP_OVERVIEW_TITLE,
-    HEAP_CHART_TITLE,
-    HEAP_CHART_TIME_AXIS,
-    HEAP_CHART_HEAP_AXIS,
-    HEAP_CHART_CAPACITY,
-    HEAP_CHART_USED,
-
-    HEAP_DUMP_SECTION_HISTOGRAM,
-    HEAP_DUMP_SECTION_OBJECT_BROWSER,
-
-    HEAP_DUMP_CLASS_USAGE,
-    HEAP_DUMP_HISTOGRAM_COLUMN_CLASS,
-    HEAP_DUMP_HISTOGRAM_COLUMN_INSTANCES,
-    HEAP_DUMP_HISTOGRAM_COLUMN_SIZE,
-
-    HEAP_DUMP_OBJECT_BROWSE_SEARCH_HINT,
-    HEAP_DUMP_OBJECT_BROWSE_SEARCH_PATTERN_HELP,
-    HEAP_DUMP_OBJECT_BROWSE_SEARCH_LABEL,
-    HEAP_DUMP_OBJECT_BROWSE_REFERRERS,
-    HEAP_DUMP_OBJECT_BROWSE_REFERENCES,
-    HEAP_DUMP_OBJECT_FIND_ROOT,
-
-    OBJECT_ROOTS_VIEW_TITLE,
-    ;
-
-    static final String RESOURCE_BUNDLE = "com.redhat.thermostat.client.heap.strings";
-
-    public static Translate<LocaleResources> createLocalizer() {
-        return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class);
-    }
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/ObjectDetailsView.java	Wed Dec 12 16:42:37 2012 +0100
+++ /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.client.heap;
-
-import java.util.Collection;
-
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.core.views.UIComponent;
-import com.redhat.thermostat.common.ActionListener;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-
-public abstract class ObjectDetailsView extends BasicView implements UIComponent {
-
-    // TODO this should be some sort of aggregate view
-    // showing users 1000 instances of a class is not very useful unless we
-    // allow the user some aggregate results or allow additional sorting or
-    // filtering
-
-    public enum ObjectAction {
-        SEARCH,
-        GET_OBJECT_DETAIL,
-        SHOW_ROOT_TO_GC,
-    }
-
-    public static interface ObjectReferenceCallback {
-        /** get a list of objects that refers to this object */
-        Collection<HeapObjectUI> getReferrers(HeapObjectUI obj);
-
-        /** get a list of objects that this object refers to */
-        Collection<HeapObjectUI> getReferences(HeapObjectUI obj);
-    }
-
-    public abstract void addObjectActionListener(ActionListener<ObjectAction> listener);
-    public abstract void removeObjectActionListnener(ActionListener<ObjectAction> listener);
-
-    public abstract void addObjectReferenceCallback(ObjectReferenceCallback callback);
-    public abstract void removeObjectReferenceCallback(ObjectReferenceCallback callback);
-
-    public abstract String getSearchText();
-
-    public abstract void setMatchingObjects(Collection<HeapObjectUI> objects);
-
-    public abstract HeapObjectUI getSelectedMatchingObject();
-
-    public abstract void setObjectDetails(JavaHeapObject object);
-
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/ObjectDetailsViewProvider.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +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.client.heap;
-
-import com.redhat.thermostat.client.core.views.ViewProvider;
-
-public interface ObjectDetailsViewProvider extends ViewProvider {
-
-    @Override
-    public ObjectDetailsView createView();
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/ObjectRootsView.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +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.client.heap;
-
-import java.util.List;
-
-import com.redhat.thermostat.client.core.views.UIComponent;
-import com.redhat.thermostat.client.core.views.View;
-import com.redhat.thermostat.common.ActionListener;
-
-public interface ObjectRootsView extends View, UIComponent {
-
-    enum Action {
-        VISIBLE,
-        HIDDEN,
-        OBJECT_SELECTED,
-    }
-
-    void addActionListener(ActionListener<Action> listener);
-    void removeActionListener(ActionListener<Action> listener);
-
-    void showView();
-    void hideView();
-
-    void setPathToRoot(List<HeapObjectUI> pathToRoot);
-    void setObjectDetails(String information);
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/ObjectRootsViewProvider.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +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.client.heap;
-
-import com.redhat.thermostat.client.core.views.ViewProvider;
-
-public interface ObjectRootsViewProvider extends ViewProvider {
-
-    @Override
-    public ObjectRootsView createView();
-    
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/chart/OverviewChart.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,173 +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.client.heap.chart;
-
-import java.awt.Color;
-import java.awt.GradientPaint;
-import java.awt.Paint;
-import java.util.Date;
-
-import javax.swing.plaf.ColorUIResource;
-
-import org.jfree.chart.ChartFactory;
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.axis.DateAxis;
-import org.jfree.chart.axis.NumberAxis;
-import org.jfree.chart.axis.TickUnits;
-import org.jfree.chart.axis.ValueAxis;
-import org.jfree.chart.plot.XYPlot;
-import org.jfree.chart.renderer.xy.XYDifferenceRenderer;
-import org.jfree.data.RangeType;
-import org.jfree.data.time.Millisecond;
-import org.jfree.data.time.TimeSeries;
-import org.jfree.data.time.TimeSeriesCollection;
-
-import com.redhat.thermostat.client.ui.BytesTickUnit;
-
-public class OverviewChart {
-        
-    private static final ColorUIResource MAIN_BAR_BASE_COLOR = new ColorUIResource(0x4A90D9);
-
-    private static final String lock = new String("chartLock");
-
-    private TimeSeries total;
-    private TimeSeries used;
-    private String title;
-    private String xAxis;
-    private String yAxis;
-    
-    public OverviewChart(String title, String xAxis, String yAxis, String mainSeries, String secondarySeries) {
-        
-        this.title = title;
-        this.xAxis = xAxis;
-        this.yAxis = yAxis;
-        
-        total = new TimeSeries(mainSeries);
-        total.setDescription(mainSeries);
-        
-        used = new TimeSeries(secondarySeries);
-        used.setDescription(secondarySeries);
-    }
-    
-    public JFreeChart createChart(int height, Color bgColor) {
-
-        TimeSeriesCollection dataset = new TimeSeriesCollection();
-        
-        synchronized (lock) {
-            dataset.addSeries(total);
-            dataset.addSeries(used);
-        }
-        
-        JFreeChart chart = ChartFactory.createTimeSeriesChart(
-                title,
-                xAxis,
-                yAxis,
-                dataset,
-                true,  // legend
-                false,  // tool tips
-                false   // URLs
-        );
-
-        Paint paint = new GradientPaint(0, 0, MAIN_BAR_BASE_COLOR, 0, height, bgColor);
-        Paint paint2 = new GradientPaint(0, 0, Color.GREEN, 0, height, bgColor);
-
-        XYPlot plot = (XYPlot) chart.getPlot();
-        plot.setDomainPannable(true);
-        XYDifferenceRenderer r = new XYDifferenceRenderer(paint, paint2, false);
-        r.setRoundXCoordinates(true);
-        plot.setDomainCrosshairLockedOnData(true);
-        plot.setRangeCrosshairLockedOnData(true);
-        plot.setDomainCrosshairVisible(true);
-        plot.setRangeCrosshairVisible(true);
-        plot.setRenderer(r);
-
-        ValueAxis domainAxis = new DateAxis(xAxis);
-        domainAxis.setLowerMargin(0.0);
-        domainAxis.setUpperMargin(0.0);
-        plot.setDomainAxis(domainAxis);
-        plot.setForegroundAlpha(0.5f);
-        TickUnits tickUnits = new TickUnits();
-        tickUnits.add(new BytesTickUnit(1.));
-        tickUnits.add(new BytesTickUnit(10.));
-        tickUnits.add(new BytesTickUnit(100.));
-        tickUnits.add(new BytesTickUnit(1000.));
-        tickUnits.add(new BytesTickUnit(10000.));
-        tickUnits.add(new BytesTickUnit(100000.));
-        tickUnits.add(new BytesTickUnit(1000000.));
-        tickUnits.add(new BytesTickUnit(10000000.));
-        tickUnits.add(new BytesTickUnit(100000000.));
-        tickUnits.add(new BytesTickUnit(1000000000.));
-        tickUnits.add(new BytesTickUnit(10000000000.));
-        tickUnits.add(new BytesTickUnit(100000000000.));
-        tickUnits.add(new BytesTickUnit(1000000000000.));
-        NumberAxis yAxis = (NumberAxis) plot.getRangeAxis();
-        yAxis.setStandardTickUnits(tickUnits);
-        yAxis.setRangeType(RangeType.POSITIVE);
-        yAxis.setAutoRangeMinimumSize(10);
-        yAxis.setAutoRange(true);
-        return chart;
-    }
-
-    public void addData(long timeStamp, long used, long total) {
-        
-        Millisecond millisecond = new Millisecond(new Date(timeStamp));
-        synchronized (lock) {            
-            if (this.total.getValue(millisecond) == null) {
-                this.total.add(millisecond, total, false);
-                this.total.removeAgedItems(true);
-            }
-            
-            if (this.used.getValue(millisecond) == null) {
-                this.used.add(millisecond, used, false);
-                this.used.removeAgedItems(true);
-            }
-        }
-        
-    }
-
-    public void notifyListenersOfModelChange() {
-        synchronized (lock) {
-            this.total.fireSeriesChanged();
-            this.used.fireSeriesChanged();
-        }
-    }
-
-    public void setRange(int seconds) {
-        total.setMaximumItemCount(seconds);
-        used.setMaximumItemCount(seconds);
-    }
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/DumpHeapCommand.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +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.client.heap.cli;
-
-import java.util.concurrent.Semaphore;
-
-import com.redhat.thermostat.client.heap.LocaleResources;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.HostVMArguments;
-import com.redhat.thermostat.common.cli.SimpleCommand;
-import com.redhat.thermostat.common.dao.AgentInfoDAO;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-
-
-public class DumpHeapCommand extends SimpleCommand {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-    private static final String NAME = "dump-heap";
-
-    private final OSGIUtils serviceProvider;
-    private final HeapDumperCommand implementation;
-
-    public DumpHeapCommand() {
-        this(OSGIUtils.getInstance(), new HeapDumperCommand());
-    }
-
-    DumpHeapCommand(OSGIUtils serviceProvider, HeapDumperCommand impl) {
-        this.serviceProvider = serviceProvider;
-        this.implementation = impl;
-    }
-
-    @Override
-    public String getName() {
-        return NAME;
-    }
-
-    @Override
-    public void run(final CommandContext ctx) throws CommandException {
-        HostVMArguments args = new HostVMArguments(ctx.getArguments());
-
-        final Semaphore s = new Semaphore(0);
-        Runnable successHandler = new Runnable() {
-            @Override
-            public void run() {
-                ctx.getConsole().getOutput().println(translator.localize(LocaleResources.COMMAND_HEAP_DUMP_DONE));
-                s.release();
-            }
-        };
-        Runnable errorHandler = new Runnable() {
-            public void run() {
-                ctx.getConsole().getError().println(translator.localize(LocaleResources.HEAP_DUMP_ERROR));
-                s.release();
-            }
-        };
-
-        AgentInfoDAO service = serviceProvider.getService(AgentInfoDAO.class);
-        if (service == null) {
-            throw new CommandException("Unable to access agent information");
-        }
-        implementation.execute(service, args.getVM(), successHandler, errorHandler);
-        serviceProvider.ungetService(AgentInfoDAO.class, service);
-
-        try {
-            s.acquire();
-        } catch (InterruptedException ex) {
-            // Nothing to do here, just return ASAP.
-        }
-    }
-
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/FindObjectsCommand.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,144 +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.client.heap.cli;
-
-import java.util.Collection;
-import java.util.List;
-
-import com.redhat.thermostat.client.heap.LocaleResources;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
-import com.redhat.thermostat.common.cli.TableRenderer;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.storage.model.HeapInfo;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-
-public class FindObjectsCommand extends SimpleCommand {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private static final String HEAP_ID_ARG = "heapId";
-    private static final String LIMIT_ARG = "limit";
-    private static final String NAME = "find-objects";
-    private static final String HEADER_OBJECT_ID = translator.localize(LocaleResources.HEADER_OBJECT_ID);
-    private static final String HEADER_TYPE = translator.localize(LocaleResources.HEADER_OBJECT_TYPE);
-    private static final int DEFAULT_LIMIT = 10;
-
-    private OSGIUtils serviceProvider;
-
-    public FindObjectsCommand() {
-        this(OSGIUtils.getInstance());
-    }
-
-    FindObjectsCommand(OSGIUtils serviceProvider) {
-        this.serviceProvider = serviceProvider;
-    }
-
-    @Override
-    public void run(CommandContext ctx) throws CommandException {
-
-        HeapDAO heapDAO = serviceProvider.getServiceAllowNull(HeapDAO.class);
-        if (heapDAO == null) {
-            throw new CommandException(translator.localize(LocaleResources.HEAP_SERVICE_UNAVAILABLE));
-        }
-        try {
-            run(ctx, heapDAO);
-        } finally {
-            serviceProvider.ungetService(HeapDAO.class, heapDAO);
-            heapDAO = null;
-        }
-    }
-
-    private void run(CommandContext ctx, HeapDAO heapDAO) throws CommandException {
-        String heapId = ctx.getArguments().getArgument(HEAP_ID_ARG);
-        HeapInfo heapInfo = heapDAO.getHeapInfo(heapId);
-        if (heapInfo == null) {
-            ctx.getConsole().getOutput().println(translator.localize(LocaleResources.HEAP_ID_NOT_FOUND, heapId));
-            return;
-        }
-        HeapDump heapDump = heapDAO.getHeapDump(heapInfo);
-        if (heapDump == null) {
-            ctx.getConsole().getOutput().println(translator.localize(LocaleResources.HEAP_ID_NOT_FOUND, heapId));
-            return;
-        }
-
-        List<String> terms = ctx.getArguments().getNonOptionArguments();
-        if (terms.size() == 0) {
-            ctx.getConsole().getOutput().println(translator.localize(LocaleResources.SEARCH_TERM_REQUIRED));
-            return;
-        }
-        String searchTerm = terms.get(0);
-        if (searchTerm.trim().length() == 0) {
-            ctx.getConsole().getOutput().println(translator.localize(LocaleResources.SEARCH_TERM_REQUIRED));
-            return;
-        }
-
-        String limitArg = ctx.getArguments().getArgument(LIMIT_ARG);
-        int limit = parseLimit(limitArg);
-        Collection<String> results = heapDump.searchObjects(searchTerm, limit);
-        TableRenderer table = new TableRenderer(2);
-        table.printLine(HEADER_OBJECT_ID, HEADER_TYPE);
-        for (String objectId : results) {
-            JavaHeapObject obj = heapDump.findObject(objectId);
-            String id = obj.getIdString();
-            String className = obj.getClazz().getName();
-            table.printLine(id, className);
-        }
-        table.render(ctx.getConsole().getOutput());
-    }
-
-    private int parseLimit(String limitArg) throws CommandException {
-        int limit = DEFAULT_LIMIT;
-        if (limitArg != null) {
-            try {
-                limit = Integer.parseInt(limitArg);
-            } catch (NumberFormatException ex) {
-                throw new CommandException(translator.localize(LocaleResources.INVALID_LIMIT, limitArg));
-            }
-        }
-        return limit;
-    }
-
-    @Override
-    public String getName() {
-        return NAME;
-    }
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/FindRoot.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +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.client.heap.cli;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-
-public class FindRoot {
-
-    private Set<JavaHeapObject> visitedObjects;
-
-    public Collection<HeapPath<JavaHeapObject>> findShortestPathsToRoot(JavaHeapObject obj, boolean findAll) {
-        HeapPath<JavaHeapObject> path = new HeapPath<>(obj);
-        List<HeapPath<JavaHeapObject>> pathsSoFar = new LinkedList<>();
-        pathsSoFar.add(path);
-        visitedObjects = new HashSet<>();
-        return findShortestPathToRoot(pathsSoFar, findAll);
-    }
-
-    private Collection<HeapPath<JavaHeapObject>> findShortestPathToRoot(List<HeapPath<JavaHeapObject>> pathsSoFar, boolean findAll) {
-        List<HeapPath<JavaHeapObject>> newPaths = new LinkedList<>();
-        Collection<HeapPath<JavaHeapObject>> roots = new ArrayList<>();
-        for (HeapPath<JavaHeapObject> path : pathsSoFar) {
-            JavaHeapObject last = path.getNode();
-            if (visitedObjects.contains(last)) {
-                continue;
-            }
-            @SuppressWarnings("rawtypes")
-            Enumeration referrers = last.getReferers();
-            while (referrers.hasMoreElements()) {
-                JavaHeapObject referrer = (JavaHeapObject) referrers.nextElement();
-                HeapPath<JavaHeapObject> newPath = new HeapPath<>(referrer, path);
-                newPaths.add(newPath);
-                if (referrer.getRoot() != null) {
-                    roots.add(newPath);
-                    if (! findAll) {
-                        return roots;
-                    }
-                }
-            }
-            visitedObjects.add(last);
-        }
-        if (newPaths.isEmpty()) {
-            return roots;
-        } else {
-            Collection<HeapPath<JavaHeapObject>> foundRoots = findShortestPathToRoot(newPaths, findAll);
-            roots.addAll(foundRoots);
-            return roots;
-        }
-    }
-
-
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/FindRootCommand.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +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.client.heap.cli;
-
-import java.io.PrintStream;
-import java.util.Collection;
-import java.util.Iterator;
-
-import com.redhat.thermostat.client.heap.LocaleResources;
-import com.redhat.thermostat.client.heap.internal.PrintObjectUtils;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-import com.sun.tools.hat.internal.model.Root;
-import com.sun.tools.hat.internal.model.Snapshot;
-
-public class FindRootCommand extends SimpleCommand {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private static final String ALL_ARG = "all";
-    private static final String NAME = "find-root";
-
-    private OSGIUtils serviceProvider;
-
-    public FindRootCommand() {
-        this(OSGIUtils.getInstance());
-    }
-
-    FindRootCommand(OSGIUtils serviceProvider) {
-        this.serviceProvider = serviceProvider;
-    }
-
-    @Override
-    public void run(CommandContext ctx) throws CommandException {
-        HeapDAO heapDao = serviceProvider.getServiceAllowNull(HeapDAO.class);
-        if (heapDao == null) {
-            throw new CommandException(translator.localize(LocaleResources.HEAP_SERVICE_UNAVAILABLE));
-        }
-
-        try {
-            run(ctx, heapDao);
-        } finally {
-            serviceProvider.ungetService(HeapDAO.class, heapDao);
-        }
-    }
-
-    private void run(CommandContext ctx, HeapDAO heapDao) throws CommandException {
-        ObjectCommandHelper objCmdHelper = new ObjectCommandHelper(ctx, heapDao);
-        HeapDump heapDump = objCmdHelper.getHeapDump();
-        Snapshot snapshot = heapDump.getSnapshot();
-        JavaHeapObject obj = objCmdHelper.getJavaHeapObject();
-        boolean findAll = ctx.getArguments().hasArgument(ALL_ARG);
-        FindRoot findRoot = new FindRoot();
-        Collection<HeapPath<JavaHeapObject>> pathsToRoot = findRoot.findShortestPathsToRoot(obj, findAll);
-        PrintStream out = ctx.getConsole().getOutput();
-        if (pathsToRoot.isEmpty()) {
-            out.println(translator.localize(LocaleResources.COMMAND_FIND_ROOT_NO_ROOT_FOUND, PrintObjectUtils.objectToString(obj)));
-        } else {
-            printPathsToRoot(snapshot, pathsToRoot, out);
-        }
-    }
-
-    private void printPathsToRoot(Snapshot snapshot, Collection<HeapPath<JavaHeapObject>> pathsToRoot, PrintStream out) {
-        for (HeapPath<JavaHeapObject> path : pathsToRoot) {
-            printPathToRoot(snapshot, path, out);
-            out.println();
-        }
-    }
-
-    private void printPathToRoot(Snapshot snapshot, HeapPath<JavaHeapObject> pathToRoot, PrintStream out) {
-        // Print root.
-        Iterator<JavaHeapObject> i = pathToRoot.iterator();
-        JavaHeapObject last = i.next();
-        Root root = last.getRoot();
-        out.println(root.getDescription() + " -> " + PrintObjectUtils.objectToString(last));
-        // Print reference 'tree'.
-        int indentation = 0;
-        while (i.hasNext()) {
-            JavaHeapObject next = i.next();
-            printIndentation(out, indentation);
-            out.print("\u2514");
-            out.print(last.describeReferenceTo(next, snapshot));
-            out.print(" in ");
-            out.print(PrintObjectUtils.objectToString(last));
-            out.print(" -> ");
-            out.println(PrintObjectUtils.objectToString(next));
-            last = next;
-            indentation++;
-        }
-    }
-
-    private void printIndentation(PrintStream out, int indentation) {
-        for (int i = 0; i < indentation; i++) {
-            out.print(" ");
-        }
-    }
-
-    @Override
-    public String getName() {
-        return NAME;
-    }
-
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommand.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +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.client.heap.cli;
-
-import java.net.InetSocketAddress;
-
-import com.redhat.thermostat.client.command.RequestQueue;
-import com.redhat.thermostat.common.command.Request;
-import com.redhat.thermostat.common.command.Request.RequestType;
-import com.redhat.thermostat.common.command.RequestResponseListener;
-import com.redhat.thermostat.common.command.Response;
-import com.redhat.thermostat.common.command.Response.ResponseType;
-import com.redhat.thermostat.common.dao.AgentInfoDAO;
-import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-
-public class HeapDumperCommand {
-    
-    private static final String RECEIVER_CLASS_NAME = "com.redhat.thermostat.agent.heapdumper.internal.HeapDumpReceiver";
-    private static final String VM_ID_PARAM = "vmId";
-
-    private class HeapDumpListener implements RequestResponseListener {
-
-        private Runnable successAction;
-        private Runnable failureAction;
-
-        private HeapDumpListener(Runnable heapDumpSuccessfulAction, Runnable heapDumpFailureAction) {
-            this.successAction = heapDumpSuccessfulAction;
-            this.failureAction = heapDumpFailureAction;
-        }
-
-        @Override
-        public void fireComplete(Request request, Response response) {
-            if (response.getType() == ResponseType.ERROR) {
-                if (failureAction != null) {
-                    failureAction.run();
-                }
-            } else {
-                if (successAction != null) {
-                    successAction.run();
-                }
-            }
-        }
-
-    }
-
-    public void execute(AgentInfoDAO agentInfoDAO, VmRef reference, Runnable heapDumpSuccessAction, Runnable heapDumpFailureAction) {
-
-        HostRef targetHostRef = reference.getAgent();
-        String address = agentInfoDAO.getAgentInformation(targetHostRef).getConfigListenAddress();
-        
-        String [] host = address.split(":");
-        InetSocketAddress target = new InetSocketAddress(host[0], Integer.parseInt(host[1]));
-        Request req = new Request(RequestType.RESPONSE_EXPECTED, target);
-        req.setReceiver(RECEIVER_CLASS_NAME);
-        req.setParameter(VM_ID_PARAM, reference.getIdString());
-        req.addListener(new HeapDumpListener(heapDumpSuccessAction, heapDumpFailureAction));
-
-        RequestQueue queue = OSGIUtils.getInstance().getService(RequestQueue.class);
-        queue.putRequest(req);
-
-    }
-
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/HeapNotFoundException.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +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.client.heap.cli;
-
-import com.redhat.thermostat.common.cli.CommandException;
-
-@SuppressWarnings("serial")
-class HeapNotFoundException extends CommandException {
-
-    private static final String MESSAGE_TEMPLATE = "Heap ID not found: ";
-
-    HeapNotFoundException(String heapId) {
-        super(MESSAGE_TEMPLATE + heapId);
-    }
-
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/HeapPath.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +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.client.heap.cli;
-
-import java.util.Iterator;
-
-public class HeapPath<T> implements Iterable<T> {
-
-    private static class HeapPathIterator<T> implements Iterator<T> {
-
-        private HeapPath<T> path;
-
-        HeapPathIterator(HeapPath<T> path) {
-            this.path = path;
-        }
-
-        @Override
-        public boolean hasNext() {
-            return path != null;
-        }
-
-        @Override
-        public T next() {
-            T next = path.node;
-            path = path.path;
-            return next;
-        }
-
-        @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-
-    }
-
-    private HeapPath<T> path;
-    private T node;
-    private int length;
-
-    HeapPath(T head) {
-        this(head, null);
-    }
-
-    HeapPath(T node, HeapPath<T> path) {
-        this.node = node;
-        this.path = path;
-        if (path != null) {
-            length = path.length + 1;
-        } else {
-            length = 1;
-        }
-    }
-
-    @Override
-    public Iterator<T> iterator() {
-        return new HeapPathIterator<T>(this);
-    }
-
-    T getNode() {
-        return node;
-    }
-
-    int getLength() {
-        return length;
-    }
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/ListHeapDumpsCommand.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +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.client.heap.cli;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-
-import com.redhat.thermostat.client.heap.LocaleResources;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.HostVMArguments;
-import com.redhat.thermostat.common.cli.SimpleCommand;
-import com.redhat.thermostat.common.cli.TableRenderer;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.dao.HostInfoDAO;
-import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.common.dao.VmInfoDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.storage.model.HeapInfo;
-
-public class ListHeapDumpsCommand extends SimpleCommand {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private static final String NAME = "list-heap-dumps";
-
-    private static final String[] COLUMN_NAMES = {
-        translator.localize(LocaleResources.HEADER_HOST_ID),
-        translator.localize(LocaleResources.HEADER_VM_ID),
-        translator.localize(LocaleResources.HEADER_HEAP_ID),
-        translator.localize(LocaleResources.HEADER_TIMESTAMP),
-    };
-
-    private final OSGIUtils serviceProvider;
-
-    public ListHeapDumpsCommand() {
-        this(OSGIUtils.getInstance());
-    }
-
-    /** For tests only */
-    ListHeapDumpsCommand(OSGIUtils serviceProvider) {
-        this.serviceProvider = serviceProvider;
-    }
-
-    @Override
-    public String getName() {
-        return NAME;
-    }
-
-    @Override
-    public void run(CommandContext ctx) throws CommandException {
-        HostVMArguments args = new HostVMArguments(ctx.getArguments(), false, false);
-
-        TableRenderer renderer = new TableRenderer(4);
-
-        renderer.printLine(COLUMN_NAMES);
-
-        HostInfoDAO hostDAO = serviceProvider.getServiceAllowNull(HostInfoDAO.class);
-        if (hostDAO == null) {
-            throw new CommandException(translator.localize(LocaleResources.HOST_SERVICE_UNAVAILABLE));
-        }
-
-        VmInfoDAO vmDAO = serviceProvider.getServiceAllowNull(VmInfoDAO.class);
-        if (vmDAO == null) {
-            throw new CommandException(translator.localize(LocaleResources.VM_SERVICE_UNAVAILABLE));
-        }
-
-        HeapDAO heapDAO = serviceProvider.getServiceAllowNull(HeapDAO.class);
-        if (heapDAO == null) {
-            throw new CommandException(translator.localize(LocaleResources.HEAP_SERVICE_UNAVAILABLE));
-        }
-
-        Collection<HostRef> hosts = args.getHost() != null ? Arrays.asList(args.getHost()) : hostDAO.getHosts();
-        for (HostRef hostRef : hosts) {
-            Collection<VmRef> vms = args.getVM() != null ? Arrays.asList(args.getVM()) : vmDAO.getVMs(hostRef);
-            for (VmRef vmRef : vms) {
-                printDumpsForVm(heapDAO, hostRef, vmRef, renderer);
-            }
-        }
-
-        serviceProvider.ungetService(HeapDAO.class, heapDAO);
-        serviceProvider.ungetService(VmInfoDAO.class, vmDAO);
-        serviceProvider.ungetService(HostInfoDAO.class, hostDAO);
-
-        renderer.render(ctx.getConsole().getOutput());
-    }
-
-    private void printDumpsForVm(HeapDAO heapDAO, HostRef hostRef, VmRef vmRef, TableRenderer renderer) {
-        Collection<HeapInfo> infos = heapDAO.getAllHeapInfo(vmRef);
-        for (HeapInfo info : infos) {
-            renderer.printLine(hostRef.getStringID(),
-                               vmRef.getStringID(),
-                               info.getHeapId(),
-                               new Date(info.getTimeStamp()).toString());
-        }
-    }
-
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/ObjectCommandHelper.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +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.client.heap.cli;
-
-import com.redhat.thermostat.client.heap.LocaleResources;
-import com.redhat.thermostat.common.cli.Arguments;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.storage.model.HeapInfo;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-
-class ObjectCommandHelper {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private static final String OBJECT_ID_ARG = "objectId";
-    private static final String HEAP_ID_ARG = "heapId";
-
-    private CommandContext ctx;
-    private HeapDAO dao;
-    private HeapDump heapDump;
-
-    ObjectCommandHelper(CommandContext ctx, HeapDAO dao) {
-        this.ctx = ctx;
-        this.dao = dao;
-    }
-
-    HeapDump getHeapDump() throws CommandException {
-        if (heapDump == null) {
-            loadHeapDump();
-        }
-        return heapDump;
-    }
-
-    private void loadHeapDump() throws CommandException {
-        Arguments args = ctx.getArguments();
-        String heapId = args.getArgument(HEAP_ID_ARG);
-        HeapInfo heapInfo = dao.getHeapInfo(heapId);
-        if (heapInfo == null) {
-            throw new CommandException(translator.localize(LocaleResources.HEAP_ID_NOT_FOUND, heapId));
-        }
-        heapDump = dao.getHeapDump(heapInfo);
-    }
-
-    JavaHeapObject getJavaHeapObject() throws CommandException {
-        HeapDump heapDump = getHeapDump();
-        Arguments args = ctx.getArguments();
-        String objectId = args.getArgument(OBJECT_ID_ARG);
-        JavaHeapObject obj = heapDump.findObject(objectId);
-        if (obj == null) {
-            throw new HeapNotFoundException(objectId);
-        }
-        return obj;
-    }
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/ObjectInfoCommand.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,147 +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.client.heap.cli;
-
-import java.io.PrintStream;
-import java.util.Enumeration;
-
-import com.redhat.thermostat.client.heap.LocaleResources;
-import com.redhat.thermostat.client.heap.internal.PrintObjectUtils;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
-import com.redhat.thermostat.common.cli.TableRenderer;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.sun.tools.hat.internal.model.JavaClass;
-import com.sun.tools.hat.internal.model.JavaField;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-import com.sun.tools.hat.internal.model.JavaHeapObjectVisitor;
-import com.sun.tools.hat.internal.model.Snapshot;
-
-public class ObjectInfoCommand extends SimpleCommand {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private static final String NAME = "object-info";
-
-    private OSGIUtils serviceProvider;
-    private Snapshot snapshot;
-
-    public ObjectInfoCommand() {
-        this(OSGIUtils.getInstance());
-    }
-
-    ObjectInfoCommand(OSGIUtils serviceProvider) {
-        this.serviceProvider = serviceProvider;
-    }
-
-    @Override
-    public void run(CommandContext ctx) throws CommandException {
-        HeapDAO heapDao = serviceProvider.getServiceAllowNull(HeapDAO.class);
-        if (heapDao == null) {
-            throw new CommandException(translator.localize(LocaleResources.HEAP_SERVICE_UNAVAILABLE));
-        }
-
-        try {
-            run(ctx, heapDao);
-        } finally {
-            serviceProvider.ungetService(HeapDAO.class, heapDao);
-        }
-    }
-
-    private void run(CommandContext ctx, HeapDAO heapDao) throws CommandException {
-        ObjectCommandHelper objCmdHelper = new ObjectCommandHelper(ctx, heapDao);
-        HeapDump heapDump = objCmdHelper.getHeapDump();
-        snapshot = heapDump.getSnapshot();
-        JavaHeapObject obj = objCmdHelper.getJavaHeapObject();
-        TableRenderer table = new TableRenderer(2);
-        table.printLine(translator.localize(LocaleResources.COMMAND_OBJECT_INFO_OBJECT_ID), obj.getIdString());
-        table.printLine(translator.localize(LocaleResources.COMMAND_OBJECT_INFO_TYPE), obj.getClazz().getName());
-        table.printLine(translator.localize(LocaleResources.COMMAND_OBJECT_INFO_SIZE), String.valueOf(obj.getSize()) + " bytes");
-        table.printLine(translator.localize(LocaleResources.COMMAND_OBJECT_INFO_HEAP_ALLOCATED), String.valueOf(obj.isHeapAllocated()));
-        table.printLine(translator.localize(LocaleResources.COMMAND_OBJECT_INFO_REFERENCES), "");
-        printReferences(table, obj);
-        table.printLine(translator.localize(LocaleResources.COMMAND_OBJECT_INFO_REFERRERS), "");
-        printReferrers(table, obj);
-
-        PrintStream out = ctx.getConsole().getOutput();
-        table.render(out);
-
-    }
-
-    private void printReferences(final TableRenderer table, final JavaHeapObject obj) {
-        JavaHeapObjectVisitor v = new JavaHeapObjectVisitor() {
-            
-            @Override
-            public void visit(JavaHeapObject ref) {
-                table.printLine("", describeReference(obj, ref) + " -> " + PrintObjectUtils.objectToString(ref));
-            }
-            
-            @Override
-            public boolean mightExclude() {
-                return false;
-            }
-            
-            @Override
-            public boolean exclude(JavaClass arg0, JavaField arg1) {
-                return false;
-            }
-        };
-        obj.visitReferencedObjects(v);
-    }
-
-    private void printReferrers(TableRenderer table, JavaHeapObject obj) {
-        Enumeration<?> referrers = obj.getReferers();
-        while (referrers.hasMoreElements()) {
-            JavaHeapObject ref = (JavaHeapObject) referrers.nextElement();
-            table.printLine("", PrintObjectUtils.objectToString(ref) + " -> " + describeReference(ref, obj));
-        }
-    }
-
-    private String describeReference(JavaHeapObject from, JavaHeapObject to) {
-        return "[" + from.describeReferenceTo(to, snapshot) + "]";
-    }
-
-    @Override
-    public String getName() {
-        return NAME;
-    }
-
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/ObjectNotFoundException.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +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.client.heap.cli;
-
-import com.redhat.thermostat.common.cli.CommandException;
-
-@SuppressWarnings("serial")
-class ObjectNotFoundException extends CommandException {
-
-    private static final String MESSAGE_TEMPLATE = "Object not found: ";
-
-    ObjectNotFoundException(String objectId) {
-        super(MESSAGE_TEMPLATE + objectId);
-    }
-
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/SaveHeapDumpToFileCommand.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,136 +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.client.heap.cli;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import com.redhat.thermostat.client.heap.LocaleResources;
-import com.redhat.thermostat.common.cli.Arguments;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.common.utils.StreamUtils;
-import com.redhat.thermostat.storage.model.HeapInfo;
-
-public class SaveHeapDumpToFileCommand extends SimpleCommand {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private static final String NAME = "save-heap-dump-to-file";
-
-    private static final String HEAP_ID_ARGUMENT = "heapId";
-    private static final String FILE_NAME_ARGUMENT = "file";
-
-    private final FileStreamCreator creator;
-    private final OSGIUtils serviceProvider;
-
-    public SaveHeapDumpToFileCommand() {
-        this(OSGIUtils.getInstance(), new FileStreamCreator());
-    }
-
-    SaveHeapDumpToFileCommand(OSGIUtils serviceProvider, FileStreamCreator creator) {
-        this.serviceProvider = serviceProvider;
-        this.creator = creator;
-    }
-
-    @Override
-    public String getName() {
-        return NAME;
-    }
-
-    @Override
-
-    public void run(CommandContext ctx) throws CommandException {
-        HeapDAO heapDAO = serviceProvider.getServiceAllowNull(HeapDAO.class);
-        try {
-            run(ctx, heapDAO);
-        } finally {
-            serviceProvider.ungetService(HeapDAO.class, heapDAO);
-            heapDAO = null;
-        }
-    }
-
-    private void run(CommandContext ctx, HeapDAO heapDAO) throws CommandException {
-        Arguments args = ctx.getArguments();
-        String heapId = args.getArgument(HEAP_ID_ARGUMENT);
-        if (heapId == null) {
-            throw new CommandException(translator.localize(LocaleResources.HEAP_ID_REQUIRED));
-        }
-        String filename = args.getArgument(FILE_NAME_ARGUMENT);
-        if (filename == null) {
-            throw new CommandException(translator.localize(LocaleResources.FILE_REQUIRED));
-        }
-
-        HeapInfo heapInfo = heapDAO.getHeapInfo(heapId);
-        try (InputStream heapStream = heapDAO.getHeapDumpData(heapInfo)) {
-            if (heapStream != null) {
-                try {
-                    saveHeapDump(heapStream, filename);
-                    ctx.getConsole().getOutput().println(translator.localize(LocaleResources.COMMAND_SAVE_HEAP_DUMP_SAVED_TO_FILE, filename));
-                } catch (IOException e) {
-                    ctx.getConsole().getOutput().println(translator.localize(LocaleResources.COMMAND_SAVE_HEAP_DUMP_ERROR_SAVING, e.getMessage()));
-                }
-            } else {
-                ctx.getConsole().getOutput().println(translator.localize(LocaleResources.HEAP_ID_NOT_FOUND, heapId));
-            }
-        } catch (IOException e) {
-            throw new CommandException(translator.localize(LocaleResources.COMMAND_SAVE_HEAP_DUMP_ERROR_CLOSING_STREAM, e.getMessage()));
-        }
-    }
-
-    private void saveHeapDump(InputStream heapStream, String filename) throws FileNotFoundException, IOException {
-        try (BufferedInputStream bis = new BufferedInputStream(heapStream);
-             BufferedOutputStream bout = new BufferedOutputStream(creator.createOutputStream(filename))) {
-            StreamUtils.copyStream(bis, bout);
-        }
-    }
-
-    static class FileStreamCreator {
-        public OutputStream createOutputStream(String filename) throws FileNotFoundException {
-            return new FileOutputStream(filename);
-        }
-    }
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/ShowHeapHistogramCommand.java	Wed Dec 12 16:42:37 2012 +0100
+++ /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.client.heap.cli;
-
-import java.io.PrintStream;
-
-import com.redhat.thermostat.client.heap.LocaleResources;
-import com.redhat.thermostat.common.cli.Arguments;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleCommand;
-import com.redhat.thermostat.common.cli.TableRenderer;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.heap.HistogramRecord;
-import com.redhat.thermostat.common.heap.ObjectHistogram;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.storage.model.HeapInfo;
-
-public class ShowHeapHistogramCommand extends SimpleCommand {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private static final String NAME = "show-heap-histogram";
-
-    private OSGIUtils serviceProvider;
-
-    public ShowHeapHistogramCommand() {
-        this(OSGIUtils.getInstance());
-    }
-
-    ShowHeapHistogramCommand(OSGIUtils serviceProvider) {
-        this.serviceProvider = serviceProvider;
-    }
-
-    @Override
-    public String getName() {
-        return NAME;
-    }
-
-    @Override
-    public void run(CommandContext ctx) throws CommandException {
-        HeapDAO heapDAO = serviceProvider.getServiceAllowNull(HeapDAO.class);
-        if (heapDAO == null) {
-            throw new CommandException(translator.localize(LocaleResources.HEAP_SERVICE_UNAVAILABLE));
-        }
-
-        try {
-            run(ctx, heapDAO);
-        } finally {
-            serviceProvider.ungetService(HeapDAO.class, heapDAO);
-        }
-    }
-
-    private void run(CommandContext ctx, HeapDAO heapDAO) throws CommandException {
-        Arguments args = ctx.getArguments();
-        String heapId = args.getArgument("heapId");
-
-        HeapInfo heapInfo = heapDAO.getHeapInfo(heapId);
-        if (heapInfo == null) {
-            ctx.getConsole().getOutput().println(translator.localize(LocaleResources.HEAP_ID_NOT_FOUND, heapId));
-            return;
-        }
-
-        ObjectHistogram histogram = heapDAO.getHistogram(heapInfo);
-        if (histogram == null) {
-            ctx.getConsole().getOutput().println(translator.localize(LocaleResources.HEAP_ID_NOT_FOUND, heapId));
-            return;
-        } else {
-            printHeapHistogram(histogram, ctx.getConsole().getOutput());
-        }
-    }
-
-    private void printHeapHistogram(ObjectHistogram histogram, PrintStream out) {
-        TableRenderer table = new TableRenderer(3);
-        for (HistogramRecord rec : histogram.getHistogram()) {
-            table.printLine(rec.getClassname(), String.valueOf(rec.getNumberOf()), String.valueOf(rec.getTotalSize()));
-        }
-        table.render(out);
-    }
-
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/internal/Activator.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +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.client.heap.internal;
-
-import java.util.ServiceLoader;
-
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-
-import com.redhat.thermostat.common.cli.Command;
-import com.redhat.thermostat.common.cli.CommandRegistry;
-import com.redhat.thermostat.common.cli.CommandRegistryImpl;
-
-public class Activator implements BundleActivator {
-
-    private CommandRegistry reg;
-
-    @Override
-    public void start(final BundleContext context) throws Exception {
-        reg = new CommandRegistryImpl(context);
-        ServiceLoader<Command> cmds = ServiceLoader.load(Command.class,
-                getClass().getClassLoader());
-        reg.registerCommands(cmds);
-    }
-
-    @Override
-    public void stop(BundleContext context) throws Exception {
-        reg.unregisterCommands();
-    }
-    
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/internal/HeapDumpDetailsController.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +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.client.heap.internal;
-
-import java.io.IOException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.heap.HeapDumpDetailsView;
-import com.redhat.thermostat.client.heap.HeapDumpDetailsViewProvider;
-import com.redhat.thermostat.client.heap.HeapHistogramView;
-import com.redhat.thermostat.client.heap.HeapHistogramViewProvider;
-import com.redhat.thermostat.client.heap.LocaleResources;
-import com.redhat.thermostat.client.heap.ObjectDetailsView;
-import com.redhat.thermostat.client.heap.ObjectDetailsViewProvider;
-import com.redhat.thermostat.client.heap.ObjectRootsViewProvider;
-import com.redhat.thermostat.common.ApplicationService;
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-
-public class HeapDumpDetailsController {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private static final Logger log = LoggingUtils.getLogger(HeapDumpDetailsController.class);
-
-    private final ApplicationService appService;
-
-    private HeapDumpDetailsView view;
-    private HeapDump heapDump;
-    private HeapHistogramViewProvider histogramViewProvider;
-    private ObjectDetailsViewProvider objectDetailsViewProvider;
-    private ObjectRootsViewProvider objectRootsViewProvider;
-
-    public HeapDumpDetailsController(ApplicationService appService, HeapDumpDetailsViewProvider viewProvider, HeapHistogramViewProvider histogramProvider, ObjectDetailsViewProvider objectDetailsProvider, ObjectRootsViewProvider objectRootsProvider) {
-        this.appService = appService;
-        this.histogramViewProvider = histogramProvider;
-        this.objectDetailsViewProvider = objectDetailsProvider;
-        this.objectRootsViewProvider = objectRootsProvider;
-        view = viewProvider.createView();
-    }
-
-    public void setDump(HeapDump dump) {
-        this.heapDump = dump;
-        try {
-            HeapHistogramView heapHistogramView = histogramViewProvider.createView();
-            heapHistogramView.display(heapDump.getHistogram());
-            String title = translator.localize(LocaleResources.HEAP_DUMP_SECTION_HISTOGRAM);
-            view.addSubView(title, heapHistogramView);
-        } catch (IOException e) {
-            log.log(Level.SEVERE, "unexpected error while reading heap dump", e);
-        }
-
-        ObjectDetailsController controller = new ObjectDetailsController(appService, dump, objectDetailsViewProvider, objectRootsViewProvider);
-        ObjectDetailsView detailsView = controller.getView();
-        view.addSubView(translator.localize(LocaleResources.HEAP_DUMP_SECTION_OBJECT_BROWSER), detailsView);
-
-        // do a dummy search right now to prep the index
-        heapDump.searchObjects("A_RANDOM_PATTERN", 1);
-    }
-
-    public BasicView getView() {
-        return view;
-    }
-
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/internal/Histogram.java	Wed Dec 12 16:42:37 2012 +0100
+++ /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.client.heap.internal;
-
-import java.util.List;
-
-public class Histogram {
-
-    private String[] header;
-    
-    private List<Object[]> data;
-    
-    Histogram(String[] header) {
-        this.header = header;
-    }
-    
-    public String[] getHistogramColums() {
-        return header;
-    }
-
-    void setData(List<Object[]> data) {
-        this.data = data;
-    }
-
-   public List<Object[]> getData() {
-    return data;
-   }
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/internal/ObjectDetailsController.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,207 +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.client.heap.internal;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.List;
-
-import com.redhat.thermostat.client.heap.HeapObjectUI;
-import com.redhat.thermostat.client.heap.ObjectDetailsView;
-import com.redhat.thermostat.client.heap.ObjectDetailsViewProvider;
-import com.redhat.thermostat.client.heap.ObjectRootsViewProvider;
-import com.redhat.thermostat.client.heap.ObjectDetailsView.ObjectAction;
-import com.redhat.thermostat.client.heap.ObjectDetailsView.ObjectReferenceCallback;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.ApplicationService;
-import com.redhat.thermostat.common.NotImplementedException;
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.sun.tools.hat.internal.model.JavaClass;
-import com.sun.tools.hat.internal.model.JavaField;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-import com.sun.tools.hat.internal.model.JavaHeapObjectVisitor;
-
-public class ObjectDetailsController {
-
-    private ApplicationService appService;
-    private HeapDump heapDump;
-    private ObjectDetailsView view;
-    private ObjectRootsViewProvider viewProvider;
-
-    public ObjectDetailsController(ApplicationService appService, HeapDump heapDump, ObjectDetailsViewProvider viewProvider, ObjectRootsViewProvider rootsViewProvider) {
-        this.appService = appService;
-        this.heapDump = heapDump;
-        this.viewProvider = rootsViewProvider;
-
-        view = viewProvider.createView();
-        addListenersToView();
-    }
-
-    private void addListenersToView() {
-
-        view.addObjectActionListener(new ActionListener<ObjectAction>() {
-            @Override
-            public void actionPerformed(ActionEvent<ObjectAction> actionEvent) {
-                switch (actionEvent.getActionId()) {
-                case SEARCH:
-                    searchForObject();
-                    break;
-                case GET_OBJECT_DETAIL:
-                    showObjectInfo();
-                    break;
-                case SHOW_ROOT_TO_GC:
-                    HeapObjectUI heapObj = (HeapObjectUI) actionEvent.getPayload();
-                    showPathToGC(heapObj);
-                    break;
-                default:
-                    throw new NotImplementedException("unknown action fired by " + actionEvent.getSource());
-                }
-
-            }
-        });
-
-        view.addObjectReferenceCallback(new ObjectReferenceCallback() {
-            @Override
-            public Collection<HeapObjectUI> getReferrers(HeapObjectUI obj) {
-                JavaHeapObject heapObject = heapDump.findObject(obj.objectId);
-
-                @SuppressWarnings("unchecked")
-                Enumeration<JavaHeapObject> referrers = heapObject.getReferers();
-
-                List<HeapObjectUI> objects = new ArrayList<>();
-                while (referrers.hasMoreElements()) {
-                    heapObject = referrers.nextElement();
-                    objects.add(new HeapObjectUI(heapObject.getIdString(), PrintObjectUtils.objectToString(heapObject)));
-                }
-                return objects;
-            }
-
-            @Override
-            public Collection<HeapObjectUI> getReferences(HeapObjectUI obj) {
-                final JavaHeapObject heapObject = heapDump.findObject(obj.objectId);
-
-                final List<JavaHeapObject> references = new ArrayList<>();
-
-                JavaHeapObjectVisitor v = new JavaHeapObjectVisitor() {
-
-                    @Override
-                    public void visit(JavaHeapObject other) {
-                        references.add(other);
-                    }
-
-                    @Override
-                    public boolean mightExclude() {
-                        /* we never return true in exclude */
-                        return false;
-                    }
-
-                    @Override
-                    public boolean exclude(JavaClass clazz, JavaField f) {
-                        /* visit every field in every java class */
-                        return false;
-                    }
-                };
-
-                heapObject.visitReferencedObjects(v);
-
-                List<HeapObjectUI> objects = new ArrayList<>();
-                for (JavaHeapObject ref: references) {
-                    objects.add(new HeapObjectUI(ref.getIdString(), PrintObjectUtils.objectToString(ref)));
-                }
-                return objects;
-            }
-        });
-    }
-
-    private void searchForObject() {
-        String searchText = view.getSearchText();
-        if (searchText == null || searchText.trim().isEmpty()) {
-            return;
-        }
-
-        final int maxResults = computeResultLimit(searchText);
-
-        if (!searchText.contains("*") && !searchText.contains("?")) {
-            searchText = "*" + searchText + "*";
-        }
-
-        final String wildcardQuery = searchText;
-
-        appService.getApplicationExecutor().execute(new Runnable() {
-
-            @Override
-            public void run() {
-                Collection<String> objectIds = heapDump.searchObjects(wildcardQuery, maxResults);
-
-                List<HeapObjectUI> toDisplay = new ArrayList<>();
-                for (String id: objectIds) {
-                    JavaHeapObject heapObject = heapDump.findObject(id);
-                    toDisplay.add(new HeapObjectUI(id, PrintObjectUtils.objectToString(heapObject)));
-                }
-                view.setMatchingObjects(toDisplay);
-            }
-        });
-
-    }
-
-    private int computeResultLimit(String searchText) {
-        return Math.min(1000, searchText.length() * 100);
-    }
-
-    private void showObjectInfo() {
-        HeapObjectUI matchingObject = view.getSelectedMatchingObject();
-        if (matchingObject == null) {
-            return;
-        }
-        String objectId = matchingObject.objectId;
-        JavaHeapObject object = heapDump.findObject(objectId);
-        view.setObjectDetails(object);
-    }
-
-    private void showPathToGC(HeapObjectUI targetObject) {
-        JavaHeapObject heapObject = heapDump.findObject(targetObject.objectId);
-
-        ObjectRootsController controller = new ObjectRootsController(heapDump, heapObject, viewProvider);
-        controller.show();
-    }
-
-    public ObjectDetailsView getView() {
-        return view;
-    }
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/internal/ObjectRootsController.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,132 +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.client.heap.internal;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-import com.redhat.thermostat.client.heap.HeapObjectUI;
-import com.redhat.thermostat.client.heap.LocaleResources;
-import com.redhat.thermostat.client.heap.ObjectRootsView;
-import com.redhat.thermostat.client.heap.ObjectRootsViewProvider;
-import com.redhat.thermostat.client.heap.ObjectRootsView.Action;
-import com.redhat.thermostat.client.heap.cli.FindRoot;
-import com.redhat.thermostat.client.heap.cli.HeapPath;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.NotImplementedException;
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.redhat.thermostat.common.locale.Translate;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-
-public class ObjectRootsController {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private final ObjectRootsView view;
-
-    private final HeapDump heapDump;
-    private final JavaHeapObject heapObject;
-    private final FindRoot rootFinder;
-
-    public ObjectRootsController(HeapDump dump, JavaHeapObject heapObject, ObjectRootsViewProvider viewProvider) {
-        this(dump, heapObject, new FindRoot(), viewProvider);
-    }
-
-    public ObjectRootsController(HeapDump dump, JavaHeapObject heapObject, FindRoot findRoot, ObjectRootsViewProvider viewProvider) {
-        this.heapDump = dump;
-        this.heapObject = heapObject;
-        this.rootFinder = findRoot;
-
-        view = viewProvider.createView();
-
-        view.addActionListener(new ActionListener<ObjectRootsView.Action>() {
-
-            @Override
-            public void actionPerformed(ActionEvent<Action> actionEvent) {
-                switch (actionEvent.getActionId()) {
-                case VISIBLE:
-                    view.showView();
-                    break;
-                case HIDDEN:
-                    view.hideView();
-                    break;
-                case OBJECT_SELECTED:
-                    HeapObjectUI obj = (HeapObjectUI) actionEvent.getPayload();
-                    showObjectDetails(obj);
-                    break;
-                default:
-                    throw new NotImplementedException("unexpected action " +
-                            actionEvent.getActionId() + " recieved by " + ObjectRootsController.this.getClass().getName());
-                }
-
-            }
-        });
-    }
-
-    private void showObjectDetails(HeapObjectUI uiObject) {
-        JavaHeapObject obj = heapDump.findObject(uiObject.objectId);
-        String text = translator.localize(LocaleResources.COMMAND_OBJECT_INFO_OBJECT_ID) + " " + obj.getIdString() + "\n" +
-                translator.localize(LocaleResources.COMMAND_OBJECT_INFO_TYPE) + " " + obj.getClazz().getName() + "\n" +
-                translator.localize(LocaleResources.COMMAND_OBJECT_INFO_SIZE) + " " + String.valueOf(obj.getSize()) + " bytes" + "\n" +
-                translator.localize(LocaleResources.COMMAND_OBJECT_INFO_HEAP_ALLOCATED) + " " + String.valueOf(obj.isHeapAllocated()) + "\n";
-
-        if (obj.getRoot() != null) {
-            text = text + obj.getRoot().getDescription();
-        }
-        view.setObjectDetails(text);
-    }
-
-
-    public void show() {
-        Collection<HeapPath<JavaHeapObject>> paths = rootFinder.findShortestPathsToRoot(heapObject, false);
-        Iterator<HeapPath<JavaHeapObject>> iter = paths.iterator();
-        if (iter.hasNext()) {
-            HeapPath<JavaHeapObject> pathToRoot = iter.next();
-
-            List<HeapObjectUI> path = new ArrayList<>();
-            for (JavaHeapObject heapObj : pathToRoot) {
-                path.add(new HeapObjectUI(heapObj.getIdString(), PrintObjectUtils.objectToString(heapObj)));
-            }
-            view.setPathToRoot(path);
-        }
-        view.showView();
-    }
-
-}
--- a/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/internal/PrintObjectUtils.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +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.client.heap.internal;
-
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-
-public class PrintObjectUtils {
-
-    public static String objectToString(JavaHeapObject obj) {
-        return obj.getClazz().getName() + "@" + obj.getIdString();
-    }
-}
--- a/client/heapdumper/core/src/main/resources/META-INF/services/com.redhat.thermostat.common.cli.Command	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-com.redhat.thermostat.client.heap.cli.DumpHeapCommand
-com.redhat.thermostat.client.heap.cli.ListHeapDumpsCommand
-com.redhat.thermostat.client.heap.cli.SaveHeapDumpToFileCommand
-com.redhat.thermostat.client.heap.cli.ShowHeapHistogramCommand
-com.redhat.thermostat.client.heap.cli.FindObjectsCommand
-com.redhat.thermostat.client.heap.cli.ObjectInfoCommand
-com.redhat.thermostat.client.heap.cli.FindRootCommand
\ No newline at end of file
--- a/client/heapdumper/core/src/main/resources/com/redhat/thermostat/client/heap/strings.properties	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-MISSING_INFO = Missing Information
-HOST_SERVICE_UNAVAILABLE = Unable to access host information (HostInfoDAO unavailable)
-VM_SERVICE_UNAVAILABLE = Unable to access vm information (VmInfoDAO unavailable)
-HEAP_SERVICE_UNAVAILABLE = Unable to access heap informatio (HeapDAO unavailable)
-
-HEADER_TIMESTAMP = TIMESTAMP
-HEADER_HOST_ID = HOST ID
-HEADER_VM_ID = VM ID
-HEADER_HEAP_ID = HEAP ID
-HEADER_OBJECT_ID = ID
-HEADER_OBJECT_TYPE = TYPE
-
-FILE_REQUIRED = A file name is required
-INVALID_LIMIT = Invalid limit {0}
-HEAP_ID_NOT_FOUND = Heap ID not found: {0}
-HEAP_ID_REQUIRED = Heap ID required
-SEARCH_TERM_REQUIRED = A search term is required
-HEAP_DUMP_ERROR = Error dumping heap (agent: {0}, vm: {1})
-
-COMMAND_HEAP_DUMP_DONE = Done
-
-COMMAND_FIND_ROOT_NO_ROOT_FOUND = No root found for: {0}
-
-COMMAND_OBJECT_INFO_OBJECT_ID = Object ID:
-COMMAND_OBJECT_INFO_TYPE = Type:
-COMMAND_OBJECT_INFO_SIZE = Size:
-COMMAND_OBJECT_INFO_HEAP_ALLOCATED = Heap allocated:
-COMMAND_OBJECT_INFO_REFERENCES = References:
-COMMAND_OBJECT_INFO_REFERRERS = Referrers:
-
-COMMAND_SAVE_HEAP_DUMP_SAVED_TO_FILE = Saved heap dump to {0}
-COMMAND_SAVE_HEAP_DUMP_ERROR_SAVING = error saving heap to file: {0}
-COMMAND_SAVE_HEAP_DUMP_ERROR_CLOSING_STREAM = error closing heap stream: {0}
-
-HEAP_SECTION_TITLE = Heap Analyzer
-HEAP_OVERVIEW_TITLE = Heap Usage Overview
-HEAP_CHART_TITLE = Used Heap vs. Heap Capacity
-HEAP_CHART_TIME_AXIS = Time
-HEAP_CHART_HEAP_AXIS = Heap
-HEAP_CHART_CAPACITY = Heap Capacity
-HEAP_CHART_USED = Used Heap
-
-HEAP_DUMP_SECTION_HISTOGRAM = Histogram
-HEAP_DUMP_SECTION_OBJECT_BROWSER = Object Browser
-
-HEAP_DUMP_CLASS_USAGE = Classes Usage
-HEAP_DUMP_HISTOGRAM_COLUMN_CLASS = Class
-HEAP_DUMP_HISTOGRAM_COLUMN_INSTANCES = Instances
-HEAP_DUMP_HISTOGRAM_COLUMN_SIZE = Size (in bytes)
-
-HEAP_DUMP_OBJECT_BROWSE_SEARCH_HINT = Search for objects by class name (either a partial class name or a wildcard pattern)
-HEAP_DUMP_OBJECT_BROWSE_SEARCH_PATTERN_HELP = Either a partial class name ("Button" will find "javax.swing.JButton") or a wildcard pattern ("*JButton*" will find "javax.swing.JButtonBeanInfo")
-HEAP_DUMP_OBJECT_BROWSE_SEARCH_LABEL = Search for Object
-HEAP_DUMP_OBJECT_BROWSE_REFERRERS = Referrers
-HEAP_DUMP_OBJECT_BROWSE_REFERENCES = References
-HEAP_DUMP_OBJECT_FIND_ROOT = Find Root
-
-OBJECT_ROOTS_VIEW_TITLE = Object Roots
\ No newline at end of file
--- a/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/HeapDumpControllerTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,420 +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.client.heap;
-
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Matchers.same;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import com.redhat.thermostat.client.heap.HeapView.HeapDumperAction;
-import com.redhat.thermostat.client.heap.cli.HeapDumperCommand;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.ApplicationCache;
-import com.redhat.thermostat.common.ApplicationService;
-import com.redhat.thermostat.common.Timer;
-import com.redhat.thermostat.common.TimerFactory;
-import com.redhat.thermostat.common.dao.AgentInfoDAO;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.redhat.thermostat.storage.model.HeapInfo;
-import com.redhat.thermostat.storage.model.VmMemoryStat;
-import com.redhat.thermostat.storage.model.VmMemoryStat.Generation;
-import com.redhat.thermostat.storage.model.VmMemoryStat.Space;
-
-public class HeapDumpControllerTest {
-
-    private ActionListener<HeapView.Action> actionListener;
-    private ActionListener<HeapView.HeapDumperAction> heapDumperListener;
-    
-    private Timer timer;
-    
-    private AgentInfoDAO agentDao;
-    private HeapDAO heapDao;
-    private VmMemoryStatDAO vmDao;
-    private HeapView view;
-    private HeapDumpDetailsView detailsView;
-    
-    @SuppressWarnings("unused")
-    private HeapDumpController controller;
-    private HeapDumperCommand heapDumperCommand;
-    private ApplicationService appService;
-    private ArgumentCaptor<Runnable> timerActionCaptor;
-    
-    private HeapViewProvider viewProvider;
-    private HeapDumpDetailsViewProvider detailsViewProvider;
-    private HeapHistogramViewProvider histogramProvider;
-    private ObjectDetailsViewProvider objectDetailsProvider;
-    private ObjectRootsViewProvider objectRootsProvider;
-
-    @Before
-    public void setUp() {
-
-        agentDao = mock(AgentInfoDAO.class);
-        heapDao = mock(HeapDAO.class);
-        vmDao = mock(VmMemoryStatDAO.class);
-        appService = mock(ApplicationService.class);
-
-        setUpView();
-    }
-    
-    private void setUpTimers() {
-        timer = mock(Timer.class);
-        timerActionCaptor = ArgumentCaptor.forClass(Runnable.class);
-        doNothing().when(timer).setAction(timerActionCaptor.capture());
-
-        TimerFactory timerFactory = mock(TimerFactory.class);
-        when(timerFactory.createTimer()).thenReturn(timer);
-        when(appService.getTimerFactory()).thenReturn(timerFactory);
-    }
-    
-    private void setUpView() {
-        view = mock(HeapView.class);
-        viewProvider = mock(HeapViewProvider.class);
-        when(viewProvider.createView()).thenReturn(view);
-        
-        detailsViewProvider = mock(HeapDumpDetailsViewProvider.class);
-        detailsView = mock(HeapDumpDetailsView.class);
-        when(detailsViewProvider.createView()).thenReturn(detailsView);
-
-        HeapHistogramView histogramView = mock(HeapHistogramView.class);
-        histogramProvider = mock(HeapHistogramViewProvider.class);
-        when(histogramProvider.createView()).thenReturn(histogramView);
-
-        ObjectDetailsView objectView = mock(ObjectDetailsView.class);
-        objectDetailsProvider = mock(ObjectDetailsViewProvider.class);
-        when(objectDetailsProvider.createView()).thenReturn(objectView);
-
-        ObjectRootsView objectRootsView = mock(ObjectRootsView.class);
-        objectRootsProvider = mock(ObjectRootsViewProvider.class);
-        when(objectRootsProvider.createView()).thenReturn(objectRootsView);
-    }
-    
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    private void setUpListeners() {        
-        ArgumentCaptor<ActionListener> viewArgumentCaptor1 = ArgumentCaptor.forClass(ActionListener.class);
-        doNothing().when(view).addActionListener(viewArgumentCaptor1.capture());
-        
-        ArgumentCaptor<ActionListener> viewArgumentCaptor2 = ArgumentCaptor.forClass(ActionListener.class);
-        doNothing().when(view).addDumperListener(viewArgumentCaptor2.capture());
-        
-        createController();
-        
-        actionListener = viewArgumentCaptor1.getValue();
-        heapDumperListener = viewArgumentCaptor2.getValue();
-    }
-    
-    private void createController() {
-        ApplicationCache cache = mock(ApplicationCache.class);
-        when(appService.getApplicationCache()).thenReturn(cache);
-        setUpTimers();
-
-        HostRef hostRef = mock(HostRef.class);
-        when(hostRef.getAgentId()).thenReturn("agent-id");
-
-        VmRef ref = mock(VmRef.class);
-        when(ref.getIdString()).thenReturn("vm-id");
-        when(ref.getAgent()).thenReturn(hostRef);
-
-        heapDumperCommand = mock(HeapDumperCommand.class);
-        controller = new HeapDumpController(agentDao, vmDao, heapDao, ref, appService,
-                heapDumperCommand, viewProvider, detailsViewProvider,
-                histogramProvider, objectDetailsProvider, objectRootsProvider);
-    }
-    
-    @After
-    public void tearDown() {
-    	controller = null;
-    	vmDao = null;
-    	heapDao = null;
-    	viewProvider = null;
-        detailsViewProvider = null;
-        histogramProvider = null;
-        objectDetailsProvider = null;
-        objectRootsProvider = null;
-        appService = null;
-    }
-
-    @Test
-    public void testTimerStartOnViewVisible() {
-        
-        setUpListeners();
-
-        actionListener.actionPerformed(new ActionEvent<>(view, HeapView.Action.VISIBLE));
-        verify(timer).start();
-    }
-
-    @Test
-    public void testTimerStopsOnViewHidden() {
-        
-        setUpListeners();
-        
-        actionListener.actionPerformed(new ActionEvent<>(view, HeapView.Action.HIDDEN));
-        verify(timer).stop();
-    }
-    
-    @Test
-    public void testNotAddHeapDumpsAtStartupWhenNoDumps() {
-                
-        when(heapDao.getAllHeapInfo(any(VmRef.class))).thenReturn(new ArrayList<HeapInfo>());
-        
-        createController();
-        
-        verify(view, times(0)).addHeapDump(any(HeapDump.class));
-    }
-    
-    @Test
-    public void testAddHeapDumpsAtStartupWhenDumpsAreThere() {
-        HeapInfo info1 = mock(HeapInfo.class);
-        HeapInfo info2 = mock(HeapInfo.class);
-        Collection<HeapInfo> infos = new ArrayList<HeapInfo>();
-        infos.add(info1);
-        infos.add(info2);
-        
-        when(heapDao.getAllHeapInfo(any(VmRef.class))).thenReturn(infos);
-
-        createController();
-        
-        verify(view, times(2)).addHeapDump(any(HeapDump.class));
-    }
-    
-    @Test
-    public void testOpenDumpCalledWhenPreviousDump() {
-
-        setUpTimers();
-        HeapDump dump = mock(HeapDump.class);
-        
-        HeapInfo info1 = mock(HeapInfo.class);
-        when(dump.getInfo()).thenReturn(info1);
-        
-        HeapInfo info2 = mock(HeapInfo.class);
-        Collection<HeapInfo> infos = new ArrayList<HeapInfo>();
-        infos.add(info1);
-        infos.add(info2);
-        
-        when(heapDao.getAllHeapInfo(any(VmRef.class))).thenReturn(infos);
-        
-        ApplicationCache cache = mock(ApplicationCache.class);
-        when(cache.getAttribute(any(VmRef.class))).thenReturn(dump);
-        when(appService.getApplicationCache()).thenReturn(cache);
-        VmRef ref = mock(VmRef.class);
-        controller = new HeapDumpController(agentDao, vmDao, heapDao, ref, appService,
-                heapDumperCommand, viewProvider, detailsViewProvider,
-                histogramProvider, objectDetailsProvider, objectRootsProvider);
-        
-        verify(view, times(1)).setChildView(any(HeapView.class));
-        verify(view, times(1)).openDumpView();
-    }
-    
-    @Test
-    public void testNotOpenDumpCalledWhenNoPreviousDump() {
-
-        setUpTimers();
-        HeapInfo info1 = mock(HeapInfo.class);        
-        HeapInfo info2 = mock(HeapInfo.class);
-        Collection<HeapInfo> infos = new ArrayList<HeapInfo>();
-        infos.add(info1);
-        infos.add(info2);
-        
-        when(heapDao.getAllHeapInfo(any(VmRef.class))).thenReturn(infos);
-        
-        ApplicationCache cache = mock(ApplicationCache.class);
-        when(cache.getAttribute(any(VmRef.class))).thenReturn(null);
-
-        when(appService.getApplicationCache()).thenReturn(cache);
-        VmRef ref = mock(VmRef.class);
-        controller = new HeapDumpController(agentDao, vmDao, heapDao, ref, appService,
-                heapDumperCommand, viewProvider, detailsViewProvider,
-                histogramProvider, objectDetailsProvider, objectRootsProvider);
-        
-        verify(view, times(0)).openDumpView();
-    }
-
-    @Test
-    public void testRequestHeapDump() {
-
-        setUpListeners();
-
-        heapDumperListener.actionPerformed(new ActionEvent<HeapDumperAction>(view, HeapDumperAction.DUMP_REQUESTED));
-
-        ArgumentCaptor<Runnable> heapDumpCompleteAction = ArgumentCaptor.forClass(Runnable.class);
-        verify(heapDumperCommand).execute(same(agentDao), any(VmRef.class), heapDumpCompleteAction.capture(), any(Runnable.class));
-        heapDumpCompleteAction.getValue().run();
-        verify(view).notifyHeapDumpComplete();
-    }
-
-    @Test
-    public void testRequestHeapDumpFails() {
-        setUpListeners();
-
-        heapDumperListener.actionPerformed(new ActionEvent<HeapDumperAction>(view, HeapDumperAction.DUMP_REQUESTED));
-
-        ArgumentCaptor<Runnable> heapDumpFailedAction = ArgumentCaptor.forClass(Runnable.class);
-        verify(heapDumperCommand).execute(same(agentDao), any(VmRef.class), any(Runnable.class), heapDumpFailedAction.capture());
-        heapDumpFailedAction.getValue().run();
-        verify(view).displayWarning("Error dumping heap (agent: agent-id, vm: vm-id)");
-    }
-
-    @SuppressWarnings("unchecked")
-	@Test
-    public void testTimerChecksForNewHeapDumps() {
-
-        HeapInfo info1 = mock(HeapInfo.class);
-        HeapInfo info2 = mock(HeapInfo.class);
-        Collection<HeapInfo> infos = new ArrayList<HeapInfo>();
-        infos.add(info1);
-        infos.add(info2);
-        
-        when(heapDao.getAllHeapInfo(any(VmRef.class))).thenReturn(infos);
-
-        createController();
-
-        timerActionCaptor.getValue().run();
-
-        @SuppressWarnings("rawtypes")
-		ArgumentCaptor<List> heapDumps = ArgumentCaptor.forClass(List.class);
-        verify(view).updateHeapDumpList(heapDumps.capture());
-        assertTrue(heapDumps.getValue().contains(new HeapDump(info1, heapDao)));
-        assertTrue(heapDumps.getValue().contains(new HeapDump(info2, heapDao)));
-    }
-
-    @Test
-    public void testTimerFetchesMemoryDataAndUpdatesView() {
-        createController();
-        Runnable timerAction = timerActionCaptor.getValue();
-
-        final long CAPACITY = 10;
-        final long USED = 5;
-        Space space = new Space();
-        space.setCapacity(CAPACITY);
-        space.setMaxCapacity(20);
-        space.setUsed(USED);
-        Generation gen = new Generation();
-        gen.setName("foobar");
-        gen.setSpaces(new Space[] { space });
-        VmMemoryStat stat = new VmMemoryStat();
-        stat.setGenerations(new Generation[] { gen });
-
-        when(vmDao.getLatestVmMemoryStats(isA(VmRef.class), anyLong())).thenReturn(Arrays.asList(stat));
-
-        timerAction.run();
-
-        ArgumentCaptor<Long> timeStampCaptor = ArgumentCaptor.forClass(Long.class);
-        verify(vmDao).getLatestVmMemoryStats(isA(VmRef.class), timeStampCaptor.capture());
-        assertTimeStampIsAround(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1), timeStampCaptor.getValue());
-        verify(view).updateUsedAndCapacity(USED + " B", CAPACITY + " B");
-    }
-
-    @Test
-    public void testTimerFetchesMemoryDataDeltaOnly() {
-        ArgumentCaptor<Long> timeStampCaptor = ArgumentCaptor.forClass(Long.class);
-
-        final long DATA_TIMESTAMP = System.currentTimeMillis() + 1000000000;
-        Space space = new Space();
-        space.setCapacity(10);
-        space.setMaxCapacity(20);
-        space.setUsed(5);
-        Generation gen = new Generation();
-        gen.setName("foobar");
-        gen.setSpaces(new Space[] { space });
-        VmMemoryStat stat = new VmMemoryStat();
-        stat.setTimeStamp(DATA_TIMESTAMP);
-        stat.setGenerations(new Generation[] { gen });
-
-        when(vmDao.getLatestVmMemoryStats(isA(VmRef.class), anyLong())).thenReturn(Arrays.asList(stat));
-
-        createController();
-        Runnable timerAction = timerActionCaptor.getValue();
-
-        timerAction.run();
-        timerAction.run();
-
-        verify(vmDao, times(2)).getLatestVmMemoryStats(isA(VmRef.class), timeStampCaptor.capture());
-
-        long timeStamp1 = timeStampCaptor.getAllValues().get(0);
-        assertTimeStampIsAround(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1), timeStamp1);
-
-        long timeStamp2 = timeStampCaptor.getAllValues().get(1);
-        assertTimeStampIsAround(DATA_TIMESTAMP, timeStamp2);
-    }
-
-    @Test
-    public void testTimerFetchesMemoryDataDeltaOnlyEvenWithNoData() {
-        ArgumentCaptor<Long> timeStampCaptor = ArgumentCaptor.forClass(Long.class);
-
-        createController();
-        Runnable timerAction = timerActionCaptor.getValue();
-
-        timerAction.run();
-        timerAction.run();
-
-        verify(vmDao, times(2)).getLatestVmMemoryStats(isA(VmRef.class), timeStampCaptor.capture());
-
-        long timeStamp1 = timeStampCaptor.getAllValues().get(0);
-        assertTimeStampIsAround(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1), timeStamp1);
-
-        long timeStamp2 = timeStampCaptor.getAllValues().get(1);
-        assertTimeStampIsAround(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1), timeStamp2);
-    }
-
-    private void assertTimeStampIsAround(long expected, long actual) {
-        assertTrue(actual <= expected + 1000);
-        assertTrue(actual >= expected - 1000);
-    }
-
-}
--- a/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/HeapDumpDetailsControllerTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,112 +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.client.heap;
-
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.io.IOException;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.client.heap.internal.HeapDumpDetailsController;
-import com.redhat.thermostat.common.ApplicationService;
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.redhat.thermostat.common.heap.ObjectHistogram;
-
-public class HeapDumpDetailsControllerTest {
-
-    private HeapDumpDetailsView view;
-    private HeapDumpDetailsViewProvider viewProvider;
-    private HeapHistogramViewProvider histogramProvider;
-    private ObjectDetailsViewProvider objectDetailsProvider;
-    private ObjectRootsViewProvider objectRootsProvider;
-
-    @Before
-    public void setUp() {
-        viewProvider = mock(HeapDumpDetailsViewProvider.class);
-        view = mock(HeapDumpDetailsView.class);
-        when(viewProvider.createView()).thenReturn(view);
-
-        HeapHistogramView histogramView = mock(HeapHistogramView.class);
-        histogramProvider = mock(HeapHistogramViewProvider.class);
-        when(histogramProvider.createView()).thenReturn(histogramView);
-
-        ObjectDetailsView objectView = mock(ObjectDetailsView.class);
-        objectDetailsProvider = mock(ObjectDetailsViewProvider.class);
-        when(objectDetailsProvider.createView()).thenReturn(objectView);
-
-        ObjectRootsView objectRootsView = mock(ObjectRootsView.class);
-        objectRootsProvider = mock(ObjectRootsViewProvider.class);
-        when(objectRootsProvider.createView()).thenReturn(objectRootsView);
-    }
-
-    @After
-    public void tearDown() {
-        viewProvider = null;
-        histogramProvider = null;
-        objectDetailsProvider = null;
-        objectRootsProvider = null;
-    }
-
-    @Test
-    public void verifyInitialize() throws IOException {
-        ApplicationService appService = mock(ApplicationService.class);
-
-        ObjectHistogram histogram = mock(ObjectHistogram.class);
-
-        HeapDump dump = mock(HeapDump.class);
-        when(dump.getHistogram()).thenReturn(histogram);
-
-        HeapDumpDetailsController controller = new HeapDumpDetailsController(
-                appService, viewProvider, histogramProvider,
-                objectDetailsProvider, objectRootsProvider);
-        controller.setDump(dump);
-
-        verify(dump).searchObjects(isA(String.class), anyInt());
-        verify(view)
-                .addSubView(isA(String.class), isA(HeapHistogramView.class));
-        verify(view)
-                .addSubView(isA(String.class), isA(ObjectDetailsView.class));
-    }
-
-}
--- a/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/LocaleResourcesTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /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.client.heap;
-
-import java.io.IOException;
-import java.util.Properties;
-
-import junit.framework.Assert;
-
-import org.junit.Test;
-
-public class LocaleResourcesTest {
-
-    @Test
-    public void testLocalizedStringsArePresent() throws IOException {
-
-        String stringsResource = "/" + LocaleResources.RESOURCE_BUNDLE.replace(".", "/") + ".properties";
-
-        Properties props = new Properties();
-        props.load(getClass().getResourceAsStream(stringsResource));
-
-        Assert.assertEquals(LocaleResources.values().length, props.values().size());
-        for (LocaleResources resource : LocaleResources.values()) {
-            Assert.assertTrue("missing property from resource bound file: " + resource,
-                              props.containsKey(resource.name()));
-        }
-    }
-}
--- a/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/ObjectDetailsControllerTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,285 +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.client.heap;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.contains;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.ExecutorService;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.InOrder;
-import org.mockito.stubbing.OngoingStubbing;
-
-import com.redhat.thermostat.client.heap.ObjectDetailsView.ObjectAction;
-import com.redhat.thermostat.client.heap.internal.ObjectDetailsController;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.ApplicationService;
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.sun.tools.hat.internal.model.JavaClass;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-
-public class ObjectDetailsControllerTest {
-
-    private ObjectDetailsView view;
-    private ApplicationService appService;
-    private ObjectRootsViewProvider objectRootsProvider;
-    private ObjectDetailsViewProvider objectDetailsProvider;
-
-    private ArgumentCaptor<Runnable> runnableCaptor;
-
-    @Before
-    public void setUp() {
-        view = mock(ObjectDetailsView.class);
-        objectDetailsProvider = mock(ObjectDetailsViewProvider.class);
-        when(objectDetailsProvider.createView()).thenReturn(view);
-        
-        objectRootsProvider = mock(ObjectRootsViewProvider.class);
-        when(objectRootsProvider.createView()).thenReturn(mock(ObjectRootsView.class));
-        runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
-        ExecutorService executorService = mock(ExecutorService.class);
-        doNothing().when(executorService).execute(runnableCaptor.capture());
-
-        appService = mock(ApplicationService.class);
-        when(appService.getApplicationExecutor()).thenReturn(executorService);
-    }
-
-    @After
-    public void tearDown() {
-        view = null;
-        objectDetailsProvider = null;
-        objectRootsProvider = null;
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Test
-    public void verifySearchWorks() {
-        final String SEARCH_TEXT = "Test";
-        final String OBJECT_ID = "0xcafebabe";
-        final String OBJECT_CLASS_NAME = "FOO";
-
-        when(view.getSearchText()).thenReturn(SEARCH_TEXT);
-
-        JavaClass heapObjectClass = mock(JavaClass.class);
-        when(heapObjectClass.getName()).thenReturn(OBJECT_CLASS_NAME);
-
-        JavaHeapObject heapObject = mock(JavaHeapObject.class);
-        when(heapObject.getIdString()).thenReturn(OBJECT_ID);
-        when(heapObject.getClazz()).thenReturn(heapObjectClass);
-
-        HeapDump dump = mock(HeapDump.class);
-        when(dump.searchObjects(contains(SEARCH_TEXT), anyInt())).thenReturn(Arrays.asList(OBJECT_ID));
-        when(dump.findObject(eq(OBJECT_ID))).thenReturn(heapObject);
-
-        ArgumentCaptor<ActionListener> viewArgumentCaptor1 = ArgumentCaptor.forClass(ActionListener.class);
-        doNothing().when(view).addObjectActionListener(viewArgumentCaptor1.capture());
-
-        @SuppressWarnings("unused")
-        ObjectDetailsController controller = new ObjectDetailsController(appService, dump, this.objectDetailsProvider, this.objectRootsProvider);
-
-        ActionListener<ObjectAction> actionListener = viewArgumentCaptor1.getValue();
-        assertNotNull(actionListener);
-        actionListener.actionPerformed(new ActionEvent<ObjectAction>(view, ObjectAction.SEARCH));
-
-        runnableCaptor.getValue().run();
-
-        ArgumentCaptor<Collection> matchingObjectsCaptor = ArgumentCaptor.forClass(Collection.class);
-        verify(view).setMatchingObjects(matchingObjectsCaptor.capture());
-
-        List<HeapObjectUI> matchingObjects = new ArrayList<HeapObjectUI>(matchingObjectsCaptor.getValue());
-        assertEquals(1, matchingObjects.size());
-        assertEquals(OBJECT_ID, matchingObjects.get(0).objectId);
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Test
-    public void verifyInputConvertedIntoWildcardsIfNeeded() {
-        HeapDump heap = mock(HeapDump.class);
-        when(view.getSearchText()).thenReturn("a");
-
-        ArgumentCaptor<ActionListener> objectActionListenerCaptor = ArgumentCaptor.forClass(ActionListener.class);
-        doNothing().when(view).addObjectActionListener(objectActionListenerCaptor.capture());
-
-        @SuppressWarnings("unused")
-        ObjectDetailsController controller = new ObjectDetailsController(appService, heap, this.objectDetailsProvider, this.objectRootsProvider);
-
-        ActionListener<ObjectAction> actionListener = objectActionListenerCaptor.getValue();
-        assertNotNull(actionListener);
-        actionListener.actionPerformed(new ActionEvent<ObjectAction>(view, ObjectAction.SEARCH));
-
-        runnableCaptor.getValue().run();
-
-        verify(heap).searchObjects("*a*", 100);
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Test
-    public void verifyWildcardInputNotConvertedIntoWildcards() {
-        HeapDump heap = mock(HeapDump.class);
-        when(view.getSearchText()).thenReturn("*a?");
-
-        ArgumentCaptor<ActionListener> objectActionListenerCaptor = ArgumentCaptor.forClass(ActionListener.class);
-        doNothing().when(view).addObjectActionListener(objectActionListenerCaptor.capture());
-
-        @SuppressWarnings("unused")
-        ObjectDetailsController controller = new ObjectDetailsController(appService, heap, this.objectDetailsProvider, this.objectRootsProvider);
-
-        ActionListener<ObjectAction> actionListener = objectActionListenerCaptor.getValue();
-        assertNotNull(actionListener);
-        actionListener.actionPerformed(new ActionEvent<ObjectAction>(view, ObjectAction.SEARCH));
-
-        runnableCaptor.getValue().run();
-
-        verify(heap).searchObjects("*a?", 300);
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Test
-    public void verifySearchLimits() {
-
-        Object[][] limits = new Object[][] {
-            { "a",       100 },
-            { "ab",      200 },
-            { "abc",     300 },
-            { "abcd",    400 },
-            { "abcde",   500 },
-            { "abcdef",  600},
-            { "abcdefg", 700},
-            { "java.lang.Class", 1000 },
-        };
-
-        HeapDump heap = mock(HeapDump.class);
-
-        OngoingStubbing<String> ongoing = when(view.getSearchText());
-        for (int i = 0; i < limits.length; i++) {
-            ongoing = ongoing.thenReturn((String)limits[i][0]);
-        }
-
-        ArgumentCaptor<ActionListener> objectActionListenerCaptor = ArgumentCaptor.forClass(ActionListener.class);
-        doNothing().when(view).addObjectActionListener(objectActionListenerCaptor.capture());
-
-        @SuppressWarnings("unused")
-        ObjectDetailsController controller = new ObjectDetailsController(appService, heap, this.objectDetailsProvider, this.objectRootsProvider);
-
-        ActionListener<ObjectAction> actionListener = objectActionListenerCaptor.getValue();
-        assertNotNull(actionListener);
-
-        for (int i = 0; i < limits.length; i++) {
-            actionListener.actionPerformed(new ActionEvent<ObjectAction>(view, ObjectAction.SEARCH));
-            runnableCaptor.getValue().run();
-        }
-
-        InOrder inOrder = inOrder(heap);
-        for (int i = 0; i < limits.length; i++) {
-            String text = (String) limits[i][0];
-            int times = (Integer) limits[i][1];
-            inOrder.verify(heap).searchObjects("*" + text + "*", times);
-        }
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Test
-    public void verifyGettingDetailsWorks() {
-        final String OBJECT_ID = "0xcafebabe";
-        final String OBJECT_ID_VISIBLE = "FOO BAR";
-
-        JavaHeapObject heapObject = mock(JavaHeapObject.class);
-
-        HeapObjectUI heapObjectRepresentation = new HeapObjectUI(OBJECT_ID, OBJECT_ID_VISIBLE);
-
-        HeapDump dump = mock(HeapDump.class);
-        when(dump.findObject(OBJECT_ID)).thenReturn(heapObject);
-
-        ArgumentCaptor<ActionListener> viewArgumentCaptor1 = ArgumentCaptor.forClass(ActionListener.class);
-        doNothing().when(view).addObjectActionListener(viewArgumentCaptor1.capture());
-
-        when(view.getSelectedMatchingObject()).thenReturn(heapObjectRepresentation);
-
-        @SuppressWarnings("unused")
-        ObjectDetailsController controller = new ObjectDetailsController(appService, dump, this.objectDetailsProvider, this.objectRootsProvider);
-
-        ActionListener<ObjectAction> actionListener = viewArgumentCaptor1.getValue();
-        assertNotNull(actionListener);
-        actionListener.actionPerformed(new ActionEvent<ObjectAction>(view, ObjectAction.GET_OBJECT_DETAIL));
-
-        verify(view).setObjectDetails(heapObject);
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Test
-    public void verifyFindRoot() {
-        final String OBJECT_ID = "0xcafebabe";
-        final String OBJECT_ID_VISIBLE = "FOO BAR";
-
-        JavaHeapObject heapObject = mock(JavaHeapObject.class);
-
-        HeapObjectUI heapObjectRepresentation = new HeapObjectUI(OBJECT_ID, OBJECT_ID_VISIBLE);
-
-        HeapDump dump = mock(HeapDump.class);
-        when(dump.findObject(OBJECT_ID)).thenReturn(heapObject);
-
-        ArgumentCaptor<ActionListener> viewArgumentCaptor1 = ArgumentCaptor.forClass(ActionListener.class);
-        doNothing().when(view).addObjectActionListener(viewArgumentCaptor1.capture());
-
-        when(view.getSelectedMatchingObject()).thenReturn(heapObjectRepresentation);
-
-        @SuppressWarnings("unused")
-        ObjectDetailsController controller = new ObjectDetailsController(appService, dump, this.objectDetailsProvider, this.objectRootsProvider);
-
-        ActionListener<ObjectAction> actionListener = viewArgumentCaptor1.getValue();
-        assertNotNull(actionListener);
-        actionListener.actionPerformed(new ActionEvent<ObjectAction>(view, ObjectAction.GET_OBJECT_DETAIL));
-
-        verify(view).setObjectDetails(heapObject);
-    }
-}
--- a/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/ObjectRootsControllerTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,151 +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.client.heap;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import com.redhat.thermostat.client.heap.ObjectRootsView.Action;
-import com.redhat.thermostat.client.heap.cli.FindRoot;
-import com.redhat.thermostat.client.heap.cli.HeapPath;
-import com.redhat.thermostat.client.heap.internal.ObjectRootsController;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.sun.tools.hat.internal.model.JavaClass;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-
-public class ObjectRootsControllerTest {
-
-    ObjectRootsController controller;
-
-    HeapDump heapDump;
-    JavaHeapObject heapObject;
-    JavaClass clazz;
-    FindRoot rootFinder;
-
-    ObjectRootsView view;
-    ActionListener<Action> listener;
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Before
-    public void setUp() {
-        // Set up views
-        view = mock(ObjectRootsView.class);
-
-        ObjectRootsViewProvider viewProvider = mock(ObjectRootsViewProvider.class);
-        when(viewProvider.createView()).thenReturn(view);
-        
-        // set up models
-        heapObject = mock(JavaHeapObject.class);
-        when(heapObject.getIdString()).thenReturn("id-string");
-
-        clazz = mock(JavaClass.class);
-        when(clazz.getName()).thenReturn("class");
-        when(heapObject.getClazz()).thenReturn(clazz);
-
-        heapDump = mock(HeapDump.class);
-        when(heapDump.findObject("test")).thenReturn(heapObject);
-
-        rootFinder = mock(FindRoot.class);
-
-        // create controller
-        controller = new ObjectRootsController(heapDump, heapObject, rootFinder, viewProvider);
-
-        ArgumentCaptor<ActionListener> listenerCaptor = ArgumentCaptor.forClass(ActionListener.class);
-        verify(view).addActionListener(listenerCaptor.capture());
-
-        listener = listenerCaptor.getValue();
-    }
-
-
-    @Test
-    public void verifyAddListenersToView() {
-        assertNotNull(listener);
-    }
-
-    @Test
-    public void verifySetObjectDetailsInView() {
-        when(heapObject.getIdString()).thenReturn("object-id");
-        when(heapObject.isHeapAllocated()).thenReturn(true);
-        when(heapObject.getSize()).thenReturn(10);
-
-        when(clazz.getName()).thenReturn("object-class");
-
-        HeapObjectUI heapObj = new HeapObjectUI("test", "test");
-        ActionEvent<Action> event = new ActionEvent<Action>(view, Action.OBJECT_SELECTED);
-        event.setPayload(heapObj);
-        listener.actionPerformed(event);
-
-        verify(view).setObjectDetails("Object ID: object-id\n" +
-                "Type: object-class\n" +
-                "Size: 10 bytes\n" +
-                "Heap allocated: true\n");
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Test
-    public void testShow() {
-
-        HeapPath<JavaHeapObject> path = mock(HeapPath.class);
-        when(path.iterator()).thenReturn(Arrays.asList(heapObject).iterator());
-
-        when(rootFinder.findShortestPathsToRoot(heapObject, false)).thenReturn(Arrays.asList(path));
-
-        controller.show();
-
-        ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
-
-        verify(view).setPathToRoot(captor.capture());
-
-        HeapObjectUI heapObj = (HeapObjectUI) captor.getValue().get(0);
-        assertEquals("id-string", heapObj.objectId);
-        assertEquals("class@id-string", heapObj.text);
-
-        verify(view).showView();
-    }
-}
--- a/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/DumpHeapCommandTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,146 +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.client.heap.cli;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import com.redhat.thermostat.common.cli.Command;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleArguments;
-import com.redhat.thermostat.common.dao.AgentInfoDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.test.TestCommandContextFactory;
-
-public class DumpHeapCommandTest {
-
-    @Test
-    public void testBasics() {
-        Command command = new DumpHeapCommand();
-        assertEquals("dump-heap", command.getName());
-        assertNotNull(command.getDescription());
-        assertNotNull(command.getUsage());
-    }
-
-    @Test
-    public void verifyAcuallyCallsWorker() throws CommandException {
-        AgentInfoDAO agentInfoDao = mock(AgentInfoDAO.class);
-        OSGIUtils osgi = mock(OSGIUtils.class);
-        when(osgi.getService(AgentInfoDAO.class)).thenReturn(agentInfoDao);
-
-        HeapDumperCommand impl = mock(HeapDumperCommand.class);
-        final ArgumentCaptor<Runnable> successHandler = ArgumentCaptor.forClass(Runnable.class);
-        doAnswer(new Answer<Void>() {
-
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                successHandler.getValue().run();
-                return null;
-            }
-        }).when(impl).execute(eq(agentInfoDao), any(VmRef.class), successHandler.capture(), any(Runnable.class));
-
-        DumpHeapCommand command = new DumpHeapCommand(osgi, impl);
-
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("hostId", "foo");
-        args.addArgument("vmId", "0");
-
-        command.run(factory.createContext(args));
-
-        verify(impl).execute(eq(agentInfoDao), isA(VmRef.class), any(Runnable.class), any(Runnable.class));
-        assertEquals("Done\n", factory.getOutput());
-    }
-
-    @Test
-    public void verifyNeedsHostAndVmId() throws CommandException {
-        AgentInfoDAO agentInfoDao = mock(AgentInfoDAO.class);
-        OSGIUtils osgi = mock(OSGIUtils.class);
-        when(osgi.getService(AgentInfoDAO.class)).thenReturn(agentInfoDao);
-
-        HeapDumperCommand impl = mock(HeapDumperCommand.class);
-        DumpHeapCommand command = new DumpHeapCommand(osgi, impl);
-
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-
-        SimpleArguments args = new SimpleArguments();
-
-        try {
-            command.run(factory.createContext(args));
-            assertTrue("should not reach here", false);
-        } catch (CommandException ce) {
-            assertEquals("a hostId is required", ce.getMessage());
-        }
-    }
-
-    @Test
-    public void verifyFailsIfAgentDaoIsNotAvailable() {
-        OSGIUtils osgi = mock(OSGIUtils.class);
-
-        HeapDumperCommand impl = mock(HeapDumperCommand.class);
-        DumpHeapCommand command = new DumpHeapCommand(osgi, impl);
-
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("hostId", "foo");
-        args.addArgument("vmId", "0");
-
-        try {
-            command.run(factory.createContext(args));
-            assertTrue("should not reach here", false);
-        } catch (CommandException ce) {
-            assertEquals("Unable to access agent information", ce.getMessage());
-        }
-    }
-
-}
--- a/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/FindObjectsCommandTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,225 +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.client.heap.cli;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.isA;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.util.Arrays;
-
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import com.redhat.thermostat.client.heap.cli.FindObjectsCommand;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleArguments;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.storage.model.HeapInfo;
-import com.redhat.thermostat.test.TestCommandContextFactory;
-import com.sun.tools.hat.internal.model.JavaClass;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-
-public class FindObjectsCommandTest {
-
-    private static final String HEAP_ID = "TEST_HEAP_ID";
-
-    private FindObjectsCommand cmd;
-
-    private HeapDump heapDump;
-
-    private HeapDAO dao;
-
-    @Before
-    public void setUp() {
-        setupHeapDump();
-
-        setupDAO();
-
-        OSGIUtils serviceProvider = mock(OSGIUtils.class);
-        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(dao);
-
-        cmd = new FindObjectsCommand(serviceProvider);
-
-    }
-
-    private void setupHeapDump() {
-        heapDump = mock(HeapDump.class);
-        JavaClass fooCls = mock(JavaClass.class);
-        when(fooCls.getName()).thenReturn("FooType");
-        JavaHeapObject fooObj = mock(JavaHeapObject.class);
-        when(fooObj.getIdString()).thenReturn("123");
-        when(fooObj.getClazz()).thenReturn(fooCls);
-        JavaClass barCls = mock(JavaClass.class);
-        when(barCls.getName()).thenReturn("BarType");
-        JavaHeapObject barObj = mock(JavaHeapObject.class);
-        when(barObj.getIdString()).thenReturn("456");
-        when(barObj.getClazz()).thenReturn(barCls);
-        JavaClass bazCls = mock(JavaClass.class);
-        when(bazCls.getName()).thenReturn("BazType");
-        JavaHeapObject bazObj = mock(JavaHeapObject.class);
-        when(bazObj.getIdString()).thenReturn("789");
-        when(bazObj.getClazz()).thenReturn(bazCls);
-
-        when(heapDump.searchObjects("fluff", 10)).thenReturn(Arrays.asList("foo", "bar", "baz"));
-        when(heapDump.searchObjects("fluff", 2)).thenReturn(Arrays.asList("foo", "bar"));
-        when(heapDump.findObject("foo")).thenReturn(fooObj);
-        when(heapDump.findObject("bar")).thenReturn(barObj);
-        when(heapDump.findObject("baz")).thenReturn(bazObj);
-    }
-
-    private void setupDAO() {
-        HeapInfo heapInfo = mock(HeapInfo.class);
-
-        dao = mock(HeapDAO.class);
-        when(dao.getHeapInfo(HEAP_ID)).thenReturn(heapInfo);
-        when(dao.getHeapDump(heapInfo)).thenReturn(heapDump);
-    }
-
-    @Test
-    public void testName() {
-        assertEquals("find-objects", cmd.getName());
-    }
-
-    @Test
-    public void testDescAndUsage() {
-        assertNotNull(cmd.getDescription());
-        assertNotNull(cmd.getUsage());
-    }
-
-    @Ignore
-    @Test
-    public void testOptions() {
-        Options options = cmd.getOptions();
-        assertEquals(2, options.getOptions().size());
-
-        assertTrue(options.hasOption("heapId"));
-        Option heapOption = options.getOption("heapId");
-        assertEquals("the ID of the heapdump to analyze", heapOption.getDescription());
-        assertTrue(heapOption.isRequired());
-        assertTrue(heapOption.hasArg());
-
-        assertTrue(options.hasOption("limit"));
-        Option limitOption = options.getOption("limit");
-        assertEquals("limit search to top N results, defaults to 10", limitOption.getDescription());
-        assertFalse(limitOption.isRequired());
-        assertTrue(limitOption.hasArg());
-    }
-
-    @Test
-    public void testStorageRequired() {
-        assertTrue(cmd.isStorageRequired());
-    }
-
-    @Test
-    public void testSimpleSearch() throws CommandException {
-
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("heapId", HEAP_ID);
-        args.addNonOptionArgument("fluff");
-
-        cmd.run(factory.createContext(args));
-
-        String expected = "ID  TYPE\n" +
-                          "123 FooType\n" +
-                          "456 BarType\n" +
-                          "789 BazType\n";
-
-        assertEquals(expected, factory.getOutput());
-
-    }
-
-    @Test
-    public void testSearchWithLimit() throws CommandException {
-
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("heapId", HEAP_ID);
-        args.addArgument("limit", "2");
-        args.addNonOptionArgument("fluff");
-
-        cmd.run(factory.createContext(args));
-
-        String expected = "ID  TYPE\n" +
-                          "123 FooType\n" +
-                          "456 BarType\n";
-
-        assertEquals(expected, factory.getOutput());
-
-    }
-
-    @Test(expected=CommandException.class)
-    public void testSearchWithInvalidLimit() throws CommandException {
-
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("heapId", HEAP_ID);
-        args.addArgument("limit", "urgs");
-        args.addNonOptionArgument("fluff");
-
-        cmd.run(factory.createContext(args));
-
-
-    }
-
-    @Test
-    public void testSearchWithBadHeapId() throws CommandException {
-        final String INVALID_HEAP_ID = "foobarbaz";
-
-        HeapDAO dao = mock(HeapDAO.class);
-        when(dao.getHeapInfo(INVALID_HEAP_ID)).thenReturn(null);
-        when(dao.getHeapDump(isA(HeapInfo.class))).thenReturn(null);
-
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("heapId", INVALID_HEAP_ID);
-
-        cmd.run(factory.createContext(args));
-
-        assertEquals("Heap ID not found: " + INVALID_HEAP_ID + "\n", factory.getOutput());
-    }
-}
--- a/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/FindRootCommandTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,345 +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.client.heap.cli;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.same;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.util.Collection;
-import java.util.Enumeration;
-
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.mockito.stubbing.OngoingStubbing;
-
-import com.redhat.thermostat.client.heap.cli.ObjectNotFoundException;
-import com.redhat.thermostat.client.heap.cli.FindRootCommand;
-import com.redhat.thermostat.client.heap.cli.HeapNotFoundException;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleArguments;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.storage.model.HeapInfo;
-import com.redhat.thermostat.test.TestCommandContextFactory;
-import com.sun.tools.hat.internal.model.JavaClass;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-import com.sun.tools.hat.internal.model.Root;
-import com.sun.tools.hat.internal.model.Snapshot;
-
-public class FindRootCommandTest {
-
-    private static final String HEAP_ID = "TEST_HEAP_ID";
-
-    private FindRootCommand cmd;
-
-    private JavaHeapObject fooObj;
-
-    private JavaHeapObject barObj;
-
-    private JavaHeapObject bazObj;
-
-    private JavaHeapObject bumObj;
-
-    private JavaHeapObject beeObj;
-
-    private HeapDAO dao;
-
-    @Before
-    public void setUp() {
-        HeapDump heapDump = setupHeapDump();
-        setupDAO(heapDump);
-
-        OSGIUtils serviceProvider = mock(OSGIUtils.class);
-        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(dao);
-
-        cmd = new FindRootCommand(serviceProvider);
-    }
-
-    @After
-    public void tearDown() {
-        fooObj = null;
-        barObj = null;
-        bazObj = null;
-        bumObj = null;
-        beeObj = null;
-        cmd = null;
-    }
-
-    @SuppressWarnings("rawtypes")
-    private HeapDump setupHeapDump() {
-        fooObj = createMockObject("FooType", "123");
-        barObj = createMockObject("BarType", "456");
-        bazObj = createMockObject("BazType", "789");
-        bumObj = createMockObject("BumType", "987");
-        beeObj = createMockObject("BeeType", "654");
-        // Setup referrer network.
-        Enumeration fooRefs = createReferrerEnum(barObj);
-        // The exception is thrown in circle-tests when we visit the foo object again.
-        when(fooObj.getReferers()).thenReturn(fooRefs).thenThrow(new RuntimeException());
-        Enumeration barRefs = createReferrerEnum(bazObj, bumObj);
-        when(barObj.getReferers()).thenReturn(barRefs);
-        Enumeration bumRefs = createReferrerEnum(beeObj);
-        when(bumObj.getReferers()).thenReturn(bumRefs);
-        Enumeration emptyRefs = createReferrerEnum();
-        when(bazObj.getReferers()).thenReturn(emptyRefs);
-        when(beeObj.getReferers()).thenReturn(emptyRefs);
-
-        // Setup referrer descriptions.
-        when(barObj.describeReferenceTo(same(fooObj), any(Snapshot.class))).thenReturn("field foo");
-        when(bazObj.describeReferenceTo(same(barObj), any(Snapshot.class))).thenReturn("field bar");
-        when(bumObj.describeReferenceTo(same(barObj), any(Snapshot.class))).thenReturn("field bar");
-        when(beeObj.describeReferenceTo(same(bumObj), any(Snapshot.class))).thenReturn("field bum");
-
-        // Setup roots.
-        Root bazRoot = mock(Root.class);
-        when(bazRoot.getDescription()).thenReturn("baz root");
-        when(bazObj.getRoot()).thenReturn(bazRoot);
-        Root beeRoot = mock(Root.class);
-        when(beeRoot.getDescription()).thenReturn("bee root");
-        when(beeObj.getRoot()).thenReturn(beeRoot);
-
-        // Setup heap dump.
-        HeapDump heapDump = mock(HeapDump.class);
-        when(heapDump.findObject("foo")).thenReturn(fooObj);
-        return heapDump;
-    }
-
-    private void setupDAO(HeapDump heapDump) {
-
-        HeapInfo heapInfo = mock(HeapInfo.class);
-
-        dao = mock(HeapDAO.class);
-        when(dao.getHeapInfo(HEAP_ID)).thenReturn(heapInfo);
-        when(dao.getHeapDump(heapInfo)).thenReturn(heapDump);
-
-    }
-
-    private JavaHeapObject createMockObject(String className, String id) {
-        JavaClass cls = mock(JavaClass.class);
-        when(cls.getName()).thenReturn(className);
-        JavaHeapObject obj = mock(JavaHeapObject.class);
-        when(obj.getIdString()).thenReturn(id);
-        when(obj.getClazz()).thenReturn(cls);
-        return obj;
-    }
-
-    @SuppressWarnings("rawtypes")
-    private Enumeration createReferrerEnum(JavaHeapObject... objs) {
-        Enumeration refs = mock(Enumeration.class);
-        OngoingStubbing<Boolean> hasMoreElements = when(refs.hasMoreElements());
-        for (int i = 0; i < objs.length; i++) {
-            hasMoreElements = hasMoreElements.thenReturn(true);
-        }
-        hasMoreElements.thenReturn(false);
-        OngoingStubbing<Object> nextElement = when(refs.nextElement());
-        for (JavaHeapObject obj : objs) {
-            nextElement = nextElement.thenReturn(obj);
-        }
-        nextElement.thenReturn(null);
-        return refs;
-    }
-
-    @Test
-    public void testName() {
-        assertEquals("find-root", cmd.getName());
-    }
-
-    @Test
-    public void testDescAndUsage() {
-        assertNotNull(cmd.getDescription());
-        assertNotNull(cmd.getUsage());
-    }
-
-    @Ignore
-    @Test
-    public void testOptions() {
-        String heapIdOption = "heapId";
-        String objectIdOption = "objectId";
-        String allOption = "all";
-        Options options = cmd.getOptions();
-        @SuppressWarnings("unchecked")
-        Collection<Options> theOptions = options.getOptions();
-        assertEquals(3, theOptions.size());
-
-        assertTrue(options.hasOption(heapIdOption));
-        Option heapOption = options.getOption(heapIdOption);
-        assertEquals("the ID of the heapdump to analyze", heapOption.getDescription());
-        assertTrue(heapOption.isRequired());
-        assertTrue(heapOption.hasArg());
-
-        assertTrue(options.hasOption(objectIdOption));
-        Option objectOption = options.getOption(objectIdOption);
-        assertEquals("the ID of the object to query", objectOption.getDescription());
-        assertTrue(heapOption.isRequired());
-        assertTrue(heapOption.hasArg());
-
-        assertTrue(options.hasOption(allOption));
-        Option all = options.getOption(allOption);
-        assertEquals("finds all paths to GC roots", all.getDescription());
-        assertFalse(all.isRequired());
-        assertFalse(all.hasArg());
-    }
-
-    @Test
-    public void testStorageRequired() {
-        assertTrue(cmd.isStorageRequired());
-    }
-
-    @Test
-    public void testSimpleAllRootsSearch() throws CommandException {
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("heapId", HEAP_ID);
-        args.addArgument("objectId", "foo");
-        args.addArgument("all", "true");
-
-        cmd.run(factory.createContext(args));
-
-        String expected = "baz root -> BazType@789\n" +
-                          "\u2514field bar in BazType@789 -> BarType@456\n" +
-                          " \u2514field foo in BarType@456 -> FooType@123\n" +
-                          "\n" +
-                          "bee root -> BeeType@654\n" +
-                          "\u2514field bum in BeeType@654 -> BumType@987\n" +
-                          " \u2514field bar in BumType@987 -> BarType@456\n" +
-                          "  \u2514field foo in BarType@456 -> FooType@123\n" +
-                          "\n";
-
-        assertEquals(expected, factory.getOutput());
-
-    }
-
-    @Test
-    public void testSimpleRootSearch() throws CommandException {
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("heapId", HEAP_ID);
-        args.addArgument("objectId", "foo");
-
-        cmd.run(factory.createContext(args));
-
-        String expected = "baz root -> BazType@789\n" +
-                          "\u2514field bar in BazType@789 -> BarType@456\n" +
-                          " \u2514field foo in BarType@456 -> FooType@123\n" +
-                          "\n";
-
-        assertEquals(expected, factory.getOutput());
-
-    }
-
-    @Test
-    public void testSearchWithoutRoot() throws CommandException {
-        when(bazObj.getRoot()).thenReturn(null);
-        when(beeObj.getRoot()).thenReturn(null);
-
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("heapId", HEAP_ID);
-        args.addArgument("objectId", "foo");
-
-        cmd.run(factory.createContext(args));
-
-        String expected = "No root found for: FooType@123\n";
-
-        assertEquals(expected, factory.getOutput());
-
-    }
-
-    @Test
-    public void testSearchWithoutRootWithCircle() throws CommandException {
-        when(bazObj.getRoot()).thenReturn(null);
-        @SuppressWarnings("rawtypes")
-        Enumeration bazReferrers = createReferrerEnum(fooObj);
-        when(bazObj.getReferers()).thenReturn(bazReferrers);
-        when(beeObj.getRoot()).thenReturn(null);
-        @SuppressWarnings("rawtypes")
-        Enumeration beeReferrers = createReferrerEnum(fooObj);
-        when(beeObj.getReferers()).thenReturn(beeReferrers);
-
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("heapId", HEAP_ID);
-        args.addArgument("objectId", "foo");
-
-        cmd.run(factory.createContext(args));
-
-        String expected = "No root found for: FooType@123\n";
-
-        assertEquals(expected, factory.getOutput());
-
-    }
-
-    public void testHeapNotFound() throws CommandException {
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("heapId", "fluff");
-        args.addArgument("objectId", "foo");
-
-        try {
-            cmd.run(factory.createContext(args));
-            fail();
-        } catch (HeapNotFoundException ex) {
-           assertEquals("Heap ID not found: fluff", ex.getMessage());
-        }
-    }
-
-    public void testObjectNotFound() throws CommandException {
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("heapId", HEAP_ID);
-        args.addArgument("objectId", "fluff");
-
-        try {
-            cmd.run(factory.createContext(args));
-            fail();
-        } catch (ObjectNotFoundException ex) {
-            assertEquals("Object not found: fluff", ex.getMessage());
-         }
-    }
-}
--- a/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommandTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,159 +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.client.heap.cli;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.net.InetSocketAddress;
-import java.util.Collection;
-
-import junit.framework.AssertionFailedError;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import com.redhat.thermostat.client.command.RequestQueue;
-import com.redhat.thermostat.common.command.Request;
-import com.redhat.thermostat.common.command.Request.RequestType;
-import com.redhat.thermostat.common.command.RequestResponseListener;
-import com.redhat.thermostat.common.command.Response;
-import com.redhat.thermostat.common.command.Response.ResponseType;
-import com.redhat.thermostat.common.dao.AgentInfoDAO;
-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.storage.model.AgentInformation;
-
-public class HeapDumperCommandTest {
-
-    private AgentInfoDAO agentInfoDao;
-    private HeapDumperCommand cmd;
-    private VmRef vmRef;
-    private RequestQueue reqQueue;
-    private Runnable heapDumpCompleteAction;
-    private Runnable heapDumpFailedAction;
-
-    @Before
-    public void setUp() {
-        reqQueue = mock(RequestQueue.class);
-        OSGIUtils osgiUtils = mock(OSGIUtils.class);
-        when(osgiUtils.getService(RequestQueue.class)).thenReturn(reqQueue);
-        OSGIUtils.setInstance(osgiUtils);
-
-        HostRef host = mock(HostRef.class);
-
-        AgentInformation agentInfo = mock(AgentInformation.class);
-        when(agentInfo.getConfigListenAddress()).thenReturn("test:123");
-
-        agentInfoDao = mock(AgentInfoDAO.class);
-        when(agentInfoDao.getAgentInformation(host)).thenReturn(agentInfo);
-
-        cmd = new HeapDumperCommand();
-        vmRef = mock(VmRef.class);
-        when(vmRef.getIdString()).thenReturn("123");
-        when(vmRef.getAgent()).thenReturn(host);
-        heapDumpCompleteAction = mock(Runnable.class);
-        heapDumpFailedAction = mock(Runnable.class);
-    }
-
-    @After
-    public void tearDown() {
-        heapDumpCompleteAction = null;
-        vmRef = null;
-        cmd = null;
-        reqQueue = null;
-    }
-
-    @Test
-	public void testExecute() {
-
-        cmd.execute(agentInfoDao, vmRef, heapDumpCompleteAction, heapDumpFailedAction);
-
-		ArgumentCaptor<Request> reqArg = ArgumentCaptor.forClass(Request.class);
-		verify(reqQueue).putRequest(reqArg.capture());
-		Request req = reqArg.getValue();
-		assertEquals("com.redhat.thermostat.agent.heapdumper.internal.HeapDumpReceiver", req.getReceiver());
-		verifyClassExists(req.getReceiver());
-		assertEquals(RequestType.RESPONSE_EXPECTED, req.getType());
-		assertEquals("123", req.getParameter("vmId"));
-		assertEquals(new InetSocketAddress("test", 123), req.getTarget());
-
-		Collection<RequestResponseListener> ls = req.getListeners();
-		for (RequestResponseListener l : ls) {
-		    l.fireComplete(req, new Response(ResponseType.OK));
-		}
-		verify(heapDumpCompleteAction).run();
-		verify(heapDumpFailedAction, times(0)).run();
-    }
-
-    @Test
-    public void testExecuteFailure() {
-
-        cmd.execute(agentInfoDao, vmRef, heapDumpCompleteAction, heapDumpFailedAction);
-
-        ArgumentCaptor<Request> reqArg = ArgumentCaptor.forClass(Request.class);
-        verify(reqQueue).putRequest(reqArg.capture());
-        Request req = reqArg.getValue();
-        assertEquals("com.redhat.thermostat.agent.heapdumper.internal.HeapDumpReceiver", req.getReceiver());
-        verifyClassExists(req.getReceiver());
-        assertEquals(RequestType.RESPONSE_EXPECTED, req.getType());
-        assertEquals("123", req.getParameter("vmId"));
-        assertEquals(new InetSocketAddress("test", 123), req.getTarget());
-
-        Collection<RequestResponseListener> ls = req.getListeners();
-        for (RequestResponseListener l : ls) {
-            l.fireComplete(req, new Response(ResponseType.ERROR));
-        }
-        verify(heapDumpCompleteAction, times(0)).run();
-        verify(heapDumpFailedAction).run();
-    }
-
-    private void verifyClassExists(String receiver) {
-        try {
-            Class.forName(receiver);
-        } catch (ClassNotFoundException e) {
-            throw new AssertionFailedError();
-        }
-    }
-
-}
--- a/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/ListHeapDumpsCommandTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,264 +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.client.heap.cli;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.TimeZone;
-
-import org.apache.commons.cli.Options;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import com.redhat.thermostat.common.cli.Command;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleArguments;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.dao.HostInfoDAO;
-import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.common.dao.VmInfoDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.storage.model.HeapInfo;
-import com.redhat.thermostat.test.TestCommandContextFactory;
-
-public class ListHeapDumpsCommandTest {
-
-    private static TimeZone defaultTimezone;
-
-    @BeforeClass
-    public static void setUpClass() {
-        defaultTimezone = TimeZone.getDefault();
-        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
-    }
-
-    @AfterClass
-    public static void tearDownClass() {
-        TimeZone.setDefault(defaultTimezone);
-    }
-
-    @Test
-    public void verifyBasics() {
-        Command command = new ListHeapDumpsCommand();
-        assertEquals("list-heap-dumps", command.getName());
-        assertNotNull(command.getDescription());
-        assertNotNull(command.getUsage());
-    }
-
-    @Ignore
-    @Test
-    public void verifyOptions() {
-        Command command = new ListHeapDumpsCommand();
-        Options options = command.getOptions();
-        assertNotNull(options);
-        assertEquals(2, options.getOptions().size());
-    }
-
-    @Test
-    public void verifyFailsWithoutHostDao() throws Exception {
-        OSGIUtils serviceProvider = mock(OSGIUtils.class);
-
-        Command command = new ListHeapDumpsCommand(serviceProvider);
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-        try {
-            command.run(factory.createContext(new SimpleArguments()));
-        } catch (CommandException hostDaoNotAvailableException) {
-            assertEquals("Unable to access host information (HostInfoDAO unavailable)",
-                    hostDaoNotAvailableException.getMessage());
-        }
-    }
-
-    @Test
-    public void verifyWorksWithoutAnyInformation() throws CommandException {
-        HostInfoDAO hostInfo = mock(HostInfoDAO.class);
-        VmInfoDAO vmInfo = mock(VmInfoDAO.class);
-        HeapDAO heapDao = mock(HeapDAO.class);
-
-        OSGIUtils serviceProvider = mock(OSGIUtils.class);
-        when(serviceProvider.getServiceAllowNull(HostInfoDAO.class)).thenReturn(hostInfo);
-        when(serviceProvider.getServiceAllowNull(VmInfoDAO.class)).thenReturn(vmInfo);
-        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(heapDao);
-
-        Command command = new ListHeapDumpsCommand(serviceProvider);
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-        command.run(factory.createContext(new SimpleArguments()));
-        assertEquals("HOST ID VM ID HEAP ID TIMESTAMP\n", factory.getOutput());
-    }
-
-    @Test
-    public void verifyWorks() throws CommandException {
-        HostRef hostRef = mock(HostRef.class);
-        when(hostRef.getStringID()).thenReturn("host-id");
-        VmRef vmRef = mock(VmRef.class);
-        when(vmRef.getStringID()).thenReturn("1");
-
-        HeapInfo heapInfo = mock(HeapInfo.class);
-        Calendar timestamp = Calendar.getInstance();
-        timestamp.set(2012, 5, 7, 15, 32, 0);
-        when(heapInfo.getTimeStamp()).thenReturn(timestamp.getTimeInMillis());
-        when(heapInfo.getHeapId()).thenReturn("0001");
-
-        HeapDAO heapDao = mock(HeapDAO.class);
-
-        VmInfoDAO vmInfo = mock(VmInfoDAO.class);
-        when(vmInfo.getVMs(hostRef)).thenReturn(Arrays.asList(vmRef));
-
-        HostInfoDAO hostInfo = mock(HostInfoDAO.class);
-        when(hostInfo.getHosts()).thenReturn(Arrays.asList(hostRef));
-
-        when(heapDao.getAllHeapInfo(vmRef)).thenReturn(Arrays.asList(heapInfo));
-
-        OSGIUtils serviceProvider = mock(OSGIUtils.class);
-        when(serviceProvider.getServiceAllowNull(HostInfoDAO.class)).thenReturn(hostInfo);
-        when(serviceProvider.getServiceAllowNull(VmInfoDAO.class)).thenReturn(vmInfo);
-        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(heapDao);
-
-        Command command = new ListHeapDumpsCommand(serviceProvider);
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-        command.run(factory.createContext(new SimpleArguments()));
-
-        String expected = "HOST ID VM ID HEAP ID TIMESTAMP\n" +
-                          "host-id 1     0001    Thu Jun 07 15:32:00 UTC 2012\n";
-
-        assertEquals(expected, factory.getOutput());
-    }
-
-    @Test
-    public void verifyWorksWithFilterOnHost() throws CommandException {
-        HostRef hostRef1 = mock(HostRef.class);
-        when(hostRef1.getStringID()).thenReturn("host1");
-        VmRef vmRef1 = mock(VmRef.class);
-        when(vmRef1.getStringID()).thenReturn("1");
-
-        HostRef hostRef2 = mock(HostRef.class);
-        when(hostRef2.getStringID()).thenReturn("host2");
-        VmRef vmRef2 = mock(VmRef.class);
-        when(vmRef2.getStringID()).thenReturn("2");
-
-        HeapInfo heapInfo = mock(HeapInfo.class);
-        Calendar timestamp = Calendar.getInstance();
-        timestamp.set(2012, 5, 7, 15, 32, 0);
-        when(heapInfo.getTimeStamp()).thenReturn(timestamp.getTimeInMillis());
-        when(heapInfo.getHeapId()).thenReturn("0001");
-
-        HeapDAO heapDao = mock(HeapDAO.class);
-
-        VmInfoDAO vmInfo = mock(VmInfoDAO.class);
-        when(vmInfo.getVMs(isA(HostRef.class))).thenReturn(Arrays.asList(vmRef1)).thenReturn(Arrays.asList(vmRef2));
-
-        HostInfoDAO hostInfo = mock(HostInfoDAO.class);
-        when(hostInfo.getHosts()).thenReturn(Arrays.asList(hostRef1, hostRef2));
-
-        when(heapDao.getAllHeapInfo(vmRef1)).thenReturn(Arrays.asList(heapInfo));
-        when(heapDao.getAllHeapInfo(vmRef2)).thenReturn(Arrays.asList(heapInfo));
-
-        OSGIUtils serviceProvider = mock(OSGIUtils.class);
-        when(serviceProvider.getServiceAllowNull(HostInfoDAO.class)).thenReturn(hostInfo);
-        when(serviceProvider.getServiceAllowNull(VmInfoDAO.class)).thenReturn(vmInfo);
-        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(heapDao);
-
-        Command command = new ListHeapDumpsCommand(serviceProvider);
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("hostId", "host1");
-
-        command.run(factory.createContext(args));
-
-        String expected = "HOST ID VM ID HEAP ID TIMESTAMP\n" +
-                          "host1   1     0001    Thu Jun 07 15:32:00 UTC 2012\n";
-
-        assertEquals(expected, factory.getOutput());
-    }
-
-    @Test
-    public void verifyWorksWithFilterOnHostAndVM() throws CommandException {
-        HostRef hostRef1 = mock(HostRef.class);
-        when(hostRef1.getStringID()).thenReturn("host1");
-        when(hostRef1.getAgentId()).thenReturn("host1");
-        VmRef vmRef1 = mock(VmRef.class);
-        when(vmRef1.getStringID()).thenReturn("1");
-
-        HostRef hostRef2 = mock(HostRef.class);
-        when(hostRef2.getStringID()).thenReturn("host2");
-        VmRef vmRef2 = mock(VmRef.class);
-        when(vmRef2.getStringID()).thenReturn("2");
-
-        HeapInfo heapInfo = mock(HeapInfo.class);
-        Calendar timestamp = Calendar.getInstance();
-        timestamp.set(2012, 5, 7, 15, 32, 0);
-        when(heapInfo.getTimeStamp()).thenReturn(timestamp.getTimeInMillis());
-        when(heapInfo.getHeapDumpId()).thenReturn("0001");
-
-        HeapDAO heapDao = mock(HeapDAO.class);
-
-        VmInfoDAO vmInfo = mock(VmInfoDAO.class);
-        when(vmInfo.getVMs(isA(HostRef.class))).thenReturn(Arrays.asList(vmRef1)).thenReturn(Arrays.asList(vmRef2));
-
-        HostInfoDAO hostInfo = mock(HostInfoDAO.class);
-        when(hostInfo.getHosts()).thenReturn(Arrays.asList(hostRef1, hostRef2));
-
-        when(heapDao.getAllHeapInfo(vmRef1)).thenReturn(Arrays.asList(heapInfo));
-        when(heapDao.getAllHeapInfo(vmRef2)).thenReturn(Arrays.asList(heapInfo));
-
-        OSGIUtils serviceProvider = mock(OSGIUtils.class);
-        when(serviceProvider.getServiceAllowNull(HostInfoDAO.class)).thenReturn(hostInfo);
-        when(serviceProvider.getServiceAllowNull(VmInfoDAO.class)).thenReturn(vmInfo);
-        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(heapDao);
-
-        Command command = new ListHeapDumpsCommand(serviceProvider);
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("hostId", "host1");
-        args.addArgument("vmId", "1"); // vm id must be an int for the arg parser to work
-
-        command.run(factory.createContext(args));
-
-        String expected = "HOST ID VM ID HEAP ID TIMESTAMP\n";
-
-        assertEquals(expected, factory.getOutput());
-    }
-}
--- a/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/ObjectInfoCommandTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,240 +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.client.heap.cli;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.same;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.util.Enumeration;
-
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import com.redhat.thermostat.client.heap.cli.HeapNotFoundException;
-import com.redhat.thermostat.client.heap.cli.ObjectInfoCommand;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleArguments;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.storage.model.HeapInfo;
-import com.redhat.thermostat.test.TestCommandContextFactory;
-import com.sun.tools.hat.internal.model.JavaClass;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-import com.sun.tools.hat.internal.model.JavaHeapObjectVisitor;
-import com.sun.tools.hat.internal.model.Snapshot;
-
-public class ObjectInfoCommandTest {
-
-    private static final String HEAP_ID = "TEST_HEAP_ID";
-
-    private ObjectInfoCommand cmd;
-    private HeapDump heapDump;
-
-    private HeapDAO dao;
-
-    @Before
-    public void setUp() {
-        setupHeapDump();
-        setupDAO();
-
-        OSGIUtils serviceProvider = mock(OSGIUtils.class);
-        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(dao);
-
-        cmd = new ObjectInfoCommand(serviceProvider);
-    }
-
-    @After
-    public void tearDown() {
-        heapDump = null;
-        cmd = null;
-    }
-
-    private void setupHeapDump() {
-        heapDump = mock(HeapDump.class);
-        JavaClass barCls = mock(JavaClass.class);
-        when(barCls.getName()).thenReturn("BarType");
-        final JavaHeapObject barObj = mock(JavaHeapObject.class);
-        when(barObj.getIdString()).thenReturn("456");
-        when(barObj.getClazz()).thenReturn(barCls);
-        JavaClass bazCls = mock(JavaClass.class);
-        when(bazCls.getName()).thenReturn("BazType");
-        final JavaHeapObject bazObj = mock(JavaHeapObject.class);
-        when(bazObj.getIdString()).thenReturn("789");
-        when(bazObj.getClazz()).thenReturn(bazCls);
-
-        JavaClass fooCls = mock(JavaClass.class);
-        when(fooCls.getName()).thenReturn("FooType");
-        JavaHeapObject fooObj = mock(JavaHeapObject.class);
-        when(fooObj.getIdString()).thenReturn("123");
-        when(fooObj.getClazz()).thenReturn(fooCls);
-        doAnswer(new Answer<Void>() {
-
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                JavaHeapObjectVisitor v = (JavaHeapObjectVisitor) invocation.getArguments()[0];
-                v.visit(barObj);
-                v.visit(bazObj);
-                return null;
-            }
-            
-        }).when(fooObj).visitReferencedObjects(any(JavaHeapObjectVisitor.class));
-        when(fooObj.describeReferenceTo(same(barObj), any(Snapshot.class))).thenReturn("field bar");
-        when(fooObj.describeReferenceTo(same(bazObj), any(Snapshot.class))).thenReturn("field baz");
-        @SuppressWarnings("rawtypes")
-        Enumeration referrerEnum = mock(Enumeration.class);
-        when(referrerEnum.hasMoreElements()).thenReturn(true).thenReturn(true).thenReturn(false);
-        when(referrerEnum.nextElement()).thenReturn(barObj).thenReturn(bazObj);
-        when(fooObj.getReferers()).thenReturn(referrerEnum);
-        when(barObj.describeReferenceTo(same(fooObj), any(Snapshot.class))).thenReturn("field foo");
-        when(bazObj.describeReferenceTo(same(fooObj), any(Snapshot.class))).thenReturn("field foo");
-        when(fooObj.isNew()).thenReturn(true);
-        when(fooObj.isHeapAllocated()).thenReturn(false);
-        when(fooObj.getSize()).thenReturn(128);
-        when(heapDump.findObject("foo")).thenReturn(fooObj);
-    }
-
-    private void setupDAO() {
-
-        HeapInfo heapInfo = mock(HeapInfo.class);
-
-        dao = mock(HeapDAO.class);
-        when(dao.getHeapInfo(HEAP_ID)).thenReturn(heapInfo);
-        when(dao.getHeapDump(heapInfo)).thenReturn(heapDump);
-    }
-
-    @Test
-    public void testName() {
-        assertEquals("object-info", cmd.getName());
-    }
-
-    @Test
-    public void testDescAndUsage() {
-        assertNotNull(cmd.getDescription());
-        assertNotNull(cmd.getUsage());
-    }
-
-    @Ignore
-    @Test
-    public void testOptions() {
-        Options options = cmd.getOptions();
-        assertEquals(2, options.getOptions().size());
-
-        assertTrue(options.hasOption("heapId"));
-        Option heapOption = options.getOption("heapId");
-        assertEquals("the ID of the heapdump to analyze", heapOption.getDescription());
-        assertTrue(heapOption.isRequired());
-        assertTrue(heapOption.hasArg());
-
-        assertTrue(options.hasOption("objectId"));
-        Option objOption = options.getOption("objectId");
-        assertEquals("the ID of the object to query", objOption.getDescription());
-        assertTrue(objOption.isRequired());
-        assertTrue(objOption.hasArg());
-    }
-
-    @Test
-    public void testStorageRequired() {
-        assertTrue(cmd.isStorageRequired());
-    }
-
-    @Test
-    public void testSimpleObject() throws CommandException {
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("heapId", HEAP_ID);
-        args.addArgument("objectId", "foo");
-
-        cmd.run(factory.createContext(args));
-
-        String expected = "Object ID:      123\n" +
-                          "Type:           FooType\n" +
-                          "Size:           128 bytes\n" +
-                          "Heap allocated: false\n" +
-                          "References:     \n" +
-                          "                [field bar] -> BarType@456\n" +
-                          "                [field baz] -> BazType@789\n" +
-                          "Referrers:      \n" +
-                          "                BarType@456 -> [field foo]\n" +
-                          "                BazType@789 -> [field foo]\n";
-
-        assertEquals(expected, factory.getOutput());
-
-    }
-
-    @Test(expected=CommandException.class)
-    public void testHeapNotFound() throws CommandException {
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("heapId", "fluff");
-        args.addArgument("objectId", "foo");
-
-        try {
-            cmd.run(factory.createContext(args));
-            fail();
-        } catch (HeapNotFoundException ex) {
-            assertEquals("Heap not found: fluff", ex.getMessage());
-        }
-    }
-
-    public void testObjectNotFound() throws CommandException {
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("heapId", HEAP_ID);
-        args.addArgument("objectId", "fluff");
-
-        try {
-            cmd.run(factory.createContext(args));
-            fail();
-        } catch (ObjectNotFoundException ex) {
-            assertEquals("Object not found: fluff", ex.getMessage());
-        }
-    }
-}
--- a/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/SaveHeapDumpToFileCommandTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,137 +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.client.heap.cli;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.FileNotFoundException;
-import java.nio.charset.Charset;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.client.heap.cli.SaveHeapDumpToFileCommand;
-import com.redhat.thermostat.client.heap.cli.SaveHeapDumpToFileCommand.FileStreamCreator;
-import com.redhat.thermostat.common.cli.Command;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleArguments;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.storage.model.HeapInfo;
-import com.redhat.thermostat.test.TestCommandContextFactory;
-
-public class SaveHeapDumpToFileCommandTest {
-
-    @Test
-    public void verifyBasicInformation() {
-        Command command = new SaveHeapDumpToFileCommand();
-        assertEquals("save-heap-dump-to-file", command.getName());
-        assertNotNull(command.getDescription());
-        assertNotNull(command.getUsage());
-    }
-
-    @Test (expected=CommandException.class)
-    public void verifyMissingHeapIdThrowsException() throws CommandException {
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("hostId", "host-id");
-        args.addArgument("vmId", "1");
-        args.addArgument("file", "heap-id-1");
-
-        OSGIUtils serviceProvider = mock(OSGIUtils.class);
-        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(mock(HeapDAO.class));
-
-        Command command = new SaveHeapDumpToFileCommand(serviceProvider, mock(FileStreamCreator.class));
-        command.run(factory.createContext(args));
-    }
-
-    @Test (expected=CommandException.class)
-    public void verifyMissingFileNameThrowsException() throws CommandException {
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("hostId", "host-id");
-        args.addArgument("vmId", "1");
-        args.addArgument("heapId", "heap-id-1");
-
-        OSGIUtils serviceProvider = mock(OSGIUtils.class);
-        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(mock(HeapDAO.class));
-
-        Command command = new SaveHeapDumpToFileCommand(serviceProvider, mock(FileStreamCreator.class));
-        command.run(factory.createContext(args));
-    }
-
-    @Test
-    public void verifyCommandWorks() throws CommandException, FileNotFoundException {
-        final String HEAP_ID = "heap-id-1";
-        final String FILE_NAME = "some-file-name";
-        final String HEAP_CONTENTS = "0xCAFEBABE";
-        final byte[] HEAP_CONTENT_BYTES = HEAP_CONTENTS.getBytes(Charset.forName("UTF-8"));
-
-        ByteArrayOutputStream heapDumpStream = new ByteArrayOutputStream();
-
-        HeapDAO heapDao = mock(HeapDAO.class);
-
-        HeapInfo info = mock(HeapInfo.class);
-        when(heapDao.getHeapInfo(HEAP_ID)).thenReturn(info);
-        when(heapDao.getHeapDumpData(info)).thenReturn(new ByteArrayInputStream(HEAP_CONTENT_BYTES));
-
-        OSGIUtils serviceProvider = mock(OSGIUtils.class);
-        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(heapDao);
-
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("heapId", HEAP_ID);
-        args.addArgument("file", FILE_NAME);
-
-        FileStreamCreator creator = mock(FileStreamCreator.class);
-        when(creator.createOutputStream(FILE_NAME)).thenReturn(heapDumpStream);
-
-        Command command = new SaveHeapDumpToFileCommand(serviceProvider, creator);
-        command.run(factory.createContext(args));
-
-        assertArrayEquals(HEAP_CONTENT_BYTES, heapDumpStream.toByteArray());
-    }
-
-}
--- a/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/ShowHeapHistogramCommandTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,140 +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.client.heap.cli;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.common.cli.Command;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.SimpleArguments;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.heap.ObjectHistogram;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.storage.model.HeapInfo;
-import com.redhat.thermostat.test.TestCommandContextFactory;
-import com.sun.tools.hat.internal.model.JavaClass;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-
-public class ShowHeapHistogramCommandTest {
-
-    @Test
-    public void verifyBasics() {
-        Command command = new ShowHeapHistogramCommand();
-
-        assertEquals("show-heap-histogram", command.getName());
-        assertNotNull(command.getDescription());
-        assertNotNull(command.getUsage());
-    }
-
-    @Test
-    public void verifyWorks() throws CommandException {
-        ObjectHistogram histo = new ObjectHistogram();
-
-        JavaClass cls1 = mock(JavaClass.class);
-        JavaHeapObject obj1 = mock(JavaHeapObject.class);
-        when(cls1.getName()).thenReturn("class1");
-        when(obj1.getClazz()).thenReturn(cls1);
-        when(obj1.getSize()).thenReturn(5);
-        JavaHeapObject obj2 = mock(JavaHeapObject.class);
-        when(obj2.getClazz()).thenReturn(cls1);
-        when(obj2.getSize()).thenReturn(3);
-        JavaClass cls2 = mock(JavaClass.class);
-        JavaHeapObject obj3 = mock(JavaHeapObject.class);
-        when(cls2.getName()).thenReturn("verylongclassnameclass2");
-        when(obj3.getClazz()).thenReturn(cls2);
-        when(obj3.getSize()).thenReturn(10);
-
-        histo.addThing(obj1);
-        histo.addThing(obj2);
-        histo.addThing(obj3);
-
-        final String HEAP_ID = "heap-id-1";
-
-        HeapDAO heapDao = mock(HeapDAO.class);
-
-        HeapInfo heapInfo = mock(HeapInfo.class);
-        when(heapDao.getHeapInfo(HEAP_ID)).thenReturn(heapInfo);
-        when(heapDao.getHistogram(heapInfo)).thenReturn(histo);
-
-        OSGIUtils serviceProvider = mock(OSGIUtils.class);
-        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(heapDao);
-
-        Command command = new ShowHeapHistogramCommand(serviceProvider);
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("heapId", HEAP_ID);
-
-        command.run(factory.createContext(args));
-
-        assertEquals("class1                  2 8\n" +
-        		     "verylongclassnameclass2 1 10\n", factory.getOutput());
-        verify(serviceProvider).ungetService(HeapDAO.class, heapDao);
-    }
-
-    @Test
-    public void verifyWorkWithBadHeapId() throws CommandException {
-        final String BAD_HEAP_ID = "invalid-heap-id";
-
-        HeapDAO heapDao = mock(HeapDAO.class);
-
-        HeapInfo heapInfo = mock(HeapInfo.class);
-        when(heapDao.getHeapInfo(BAD_HEAP_ID)).thenReturn(null);
-        when(heapDao.getHistogram(any(HeapInfo.class))).thenReturn(null);
-
-        OSGIUtils serviceProvider = mock(OSGIUtils.class);
-        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(heapDao);
-
-        Command command = new ShowHeapHistogramCommand(serviceProvider);
-        TestCommandContextFactory factory = new TestCommandContextFactory();
-
-        SimpleArguments args = new SimpleArguments();
-        args.addArgument("heapId", BAD_HEAP_ID);
-
-        command.run(factory.createContext(args));
-
-        assertEquals("Heap ID not found: " + BAD_HEAP_ID + "\n", factory.getOutput());
-        verify(serviceProvider).ungetService(HeapDAO.class, heapDao);
-    }
-}
--- a/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/internal/ActivatorTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +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.client.heap.internal;
-
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.mock;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.FrameworkUtil;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-
-import com.redhat.thermostat.client.heap.cli.DumpHeapCommand;
-import com.redhat.thermostat.client.heap.cli.FindObjectsCommand;
-import com.redhat.thermostat.client.heap.cli.FindRootCommand;
-import com.redhat.thermostat.client.heap.cli.ListHeapDumpsCommand;
-import com.redhat.thermostat.client.heap.cli.ObjectInfoCommand;
-import com.redhat.thermostat.client.heap.cli.SaveHeapDumpToFileCommand;
-import com.redhat.thermostat.client.heap.cli.ShowHeapHistogramCommand;
-import com.redhat.thermostat.common.cli.Command;
-import com.redhat.thermostat.test.StubBundleContext;
-import com.redhat.thermostat.tools.cli.ShellCommand;
-
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(FrameworkUtil.class)
-public class ActivatorTest {
-
-    @Test
-    public void testCommandsRegistered() throws Exception {
-        /*
-         * ServiceLoader pulls in all commands from bundles on the classpath.
-         * During maven builds the tools bundle is on the classpath which uses
-         * the no-arg constructor of ShellCommand. That in turn uses
-         * FrameworkUtil. We need to mock FrameworkUtil here in order to avoid
-         * that throwing NPEs.
-         */
-        PowerMockito.mockStatic(FrameworkUtil.class);
-        Bundle mockBundle = mock(Bundle.class);
-        when(FrameworkUtil.getBundle(ShellCommand.class)).thenReturn(mockBundle);
-        StubBundleContext ctx = new StubBundleContext();
-        when(mockBundle.getBundleContext()).thenReturn(ctx);
-        Activator activator = new Activator();
-        
-        activator.start(ctx);
-        
-        assertTrue(ctx.isServiceRegistered(Command.class.getName(), DumpHeapCommand.class));
-        assertTrue(ctx.isServiceRegistered(Command.class.getName(), FindObjectsCommand.class));
-        assertTrue(ctx.isServiceRegistered(Command.class.getName(), FindRootCommand.class));
-        assertTrue(ctx.isServiceRegistered(Command.class.getName(), ListHeapDumpsCommand.class));
-        assertTrue(ctx.isServiceRegistered(Command.class.getName(), ObjectInfoCommand.class));
-        assertTrue(ctx.isServiceRegistered(Command.class.getName(), SaveHeapDumpToFileCommand.class));
-        assertTrue(ctx.isServiceRegistered(Command.class.getName(), ShowHeapHistogramCommand.class));
-    }
-}
--- a/client/heapdumper/pom.xml	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-<?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-client</artifactId>
-    <version>0.5.0-SNAPSHOT</version>
-  </parent>
-
-  <artifactId>thermostat-client-heapdumper</artifactId>
-  <packaging>pom</packaging>
-
-  <name>Thermostat Client Heap Dumper plugin</name>
-
-  <modules>
-    <module>core</module>
-    <module>swing</module>
-  </modules>
-
-</project>
--- a/client/heapdumper/swing/pom.xml	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,144 +0,0 @@
-<?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>
-    <artifactId>thermostat-client-heapdumper</artifactId>
-    <groupId>com.redhat.thermostat</groupId>
-    <version>0.5.0-SNAPSHOT</version>
-  </parent>
-  <artifactId>thermostat-client-heapdumper-swing</artifactId>
-  <packaging>bundle</packaging>
-  <name>Thermostat Client Heap Dumper Swing plugin</name>
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <configuration>
-          <instructions>
-            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
-            <Bundle-Activator>com.redhat.thermostat.client.heap.swing.Activator</Bundle-Activator>
-            <Bundle-SymbolicName>com.redhat.thermostat.client.heapdumper.swing</Bundle-SymbolicName>
-            <Private-Package>
-               com.redhat.thermostat.client.heap.swing
-            </Private-Package>
-            <!-- Do not autogenerate uses clauses in Manifests -->
-            <_nouses>true</_nouses>
-          </instructions>
-        </configuration>
-      </plugin>
-    </plugins>
-  </build>
-  <dependencies>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.mockito</groupId>
-      <artifactId>mockito-core</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.easytesting</groupId>
-      <artifactId>fest-swing</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>net.java.openjdk.cacio</groupId>
-      <artifactId>cacio-tta</artifactId>
-      <scope>test</scope>
-    </dependency>
-    
-    <dependency>
-      <groupId>org.osgi</groupId>
-      <artifactId>org.osgi.core</artifactId>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.osgi</groupId>
-      <artifactId>org.osgi.compendium</artifactId>
-      <scope>provided</scope>
-    </dependency>
-    
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-common-core</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-client-swing</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-tools</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-client-heapdumper-core</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-agent-heapdumper</artifactId>
-      <version>${project.version}</version>
-      <scope>test</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>org.jfree</groupId>
-      <artifactId>jfreechart</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>com.sun</groupId>
-      <artifactId>tools</artifactId>
-      <scope>system</scope>
-      <systemPath>${java.home}/../lib/tools.jar</systemPath>
-    </dependency>
-    
-  </dependencies>
-</project>
--- a/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/Activator.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +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.client.heap.swing;
-
-import java.util.Map;
-import java.util.Objects;
-
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-
-import com.redhat.thermostat.client.core.VmInformationService;
-import com.redhat.thermostat.client.heap.HeapDumperService;
-import com.redhat.thermostat.common.ApplicationService;
-import com.redhat.thermostat.common.MultipleServiceTracker;
-import com.redhat.thermostat.common.MultipleServiceTracker.Action;
-import com.redhat.thermostat.common.dao.AgentInfoDAO;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
-
-public class Activator implements BundleActivator {
-
-    private MultipleServiceTracker heapDumperServiceTracker;
-    private ServiceRegistration heapDumperServiceRegistration;
-    private BundleContext context;
-
-    @Override
-    public void start(final BundleContext context) throws Exception {
-
-        this.context = context;
-        Class<?>[] deps = new Class<?>[] {
-                ApplicationService.class,
-                AgentInfoDAO.class,
-                VmMemoryStatDAO.class,
-                HeapDAO.class,
-        };
-
-        heapDumperServiceTracker = new MultipleServiceTracker(context, deps,
-                getServiceAvailableAction());
-        heapDumperServiceTracker.open();
-    }
-
-    @Override
-    public void stop(BundleContext context) throws Exception {
-        heapDumperServiceTracker.close();
-    }
-    
-    // package private for testing
-    ServicesAvailableAction getServiceAvailableAction() {
-        return new ServicesAvailableAction();
-    }
-    
-    class ServicesAvailableAction implements Action {
-
-        @Override
-        public void dependenciesAvailable(Map<String, Object> services) {
-            ApplicationService appService = (ApplicationService) services
-                    .get(ApplicationService.class.getName());
-            Objects.requireNonNull(appService);
-            AgentInfoDAO agentDao = (AgentInfoDAO) services
-                    .get(AgentInfoDAO.class.getName());
-            Objects.requireNonNull(agentDao);
-            VmMemoryStatDAO vmMemoryStatDao = (VmMemoryStatDAO) services
-                    .get(VmMemoryStatDAO.class.getName());
-            Objects.requireNonNull(vmMemoryStatDao);
-            HeapDAO heapDao = (HeapDAO) services.get(HeapDAO.class.getName());
-            Objects.requireNonNull(heapDao);
-            heapDumperServiceRegistration = context
-                    .registerService(VmInformationService.class
-                            .getName(), new HeapDumperService(
-                            appService, agentDao, vmMemoryStatDao, heapDao,
-                            new SwingHeapDumpDetailsViewProvider(),
-                            new SwingHeapViewProvider(),
-                            new SwingHeapHistogramViewProvider(),
-                            new SwingObjectDetailsViewProvider(),
-                            new SwingObjectRootsViewProvider()),
-                            null);
-            
-        }
-
-        @Override
-        public void dependenciesUnavailable() {
-            heapDumperServiceRegistration.unregister();
-        }
-        
-    }
-}
--- a/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/HeapDetailsSwing.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +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.client.heap.swing;
-
-import java.awt.BorderLayout;
-
-import javax.swing.JPanel;
-import javax.swing.JTabbedPane;
-import javax.swing.SwingUtilities;
-
-import com.redhat.thermostat.client.heap.HeapDumpDetailsView;
-import com.redhat.thermostat.client.heap.HeapHistogramView;
-import com.redhat.thermostat.client.heap.ObjectDetailsView;
-import com.redhat.thermostat.client.swing.SwingComponent;
-
-public class HeapDetailsSwing extends HeapDumpDetailsView implements SwingComponent {
-
-    /** For TESTING only! */
-    static final String TAB_NAME = "tabs";
-
-    private JPanel visiblePane;
-
-    private JTabbedPane tabPane = new JTabbedPane();
-
-    public HeapDetailsSwing() {
-        visiblePane = new JPanel();
-        visiblePane.setLayout(new BorderLayout());
-        visiblePane.add(tabPane, BorderLayout.CENTER);
-
-        tabPane.setName(TAB_NAME);
-    }
-
-    @Override
-    public void addSubView(final String title, final HeapHistogramView view) {
-        verifyIsSwingComponent(view);
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                tabPane.insertTab(title, null, ((SwingComponent)view).getUiComponent(), null, 0);
-            }
-        });
-    }
-
-    @Override
-    public void addSubView(final String title, final ObjectDetailsView view) {
-        verifyIsSwingComponent(view);
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                tabPane.insertTab(title, null, ((SwingComponent)view).getUiComponent(), null, 1);
-            }
-        });
-    }
-
-    @Override
-    public void removeSubView(final String title) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                int tabCount = tabPane.getTabCount();
-                for (int i = 0; i < tabCount; i++) {
-                    String tabTitle = tabPane.getTitleAt(i);
-                    if (tabTitle.equals(title)) {
-                        tabPane.removeTabAt(i);
-                        return;
-                    }
-                }
-            }
-        });
-    }
-
-    @Override
-    public JPanel getUiComponent() {
-        return visiblePane;
-    }
-
-    private void verifyIsSwingComponent(Object obj) {
-        if (!(obj instanceof SwingComponent)) {
-            throw new IllegalArgumentException("component is not swing");
-        }
-    }
-
-}
--- a/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/HeapPanel.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +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.client.heap.swing;
-
-import java.awt.Dimension;
-
-import javax.swing.JPanel;
-import javax.swing.JSplitPane;
-import javax.swing.GroupLayout;
-import javax.swing.GroupLayout.Alignment;
-
-@SuppressWarnings("serial")
-public class HeapPanel extends JPanel {
-
-    private JSplitPane splitPane;
-    
-    public HeapPanel() {
-        
-        splitPane = new JSplitPane();
-        splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
-        GroupLayout groupLayout = new GroupLayout(this);
-        groupLayout.setHorizontalGroup(
-            groupLayout.createParallelGroup(Alignment.LEADING)
-                .addComponent(splitPane, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 450, Short.MAX_VALUE)
-        );
-        groupLayout.setVerticalGroup(
-            groupLayout.createParallelGroup(Alignment.LEADING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addGap(5)
-                    .addComponent(splitPane, GroupLayout.DEFAULT_SIZE, 295, Short.MAX_VALUE))
-        );
-
-        splitPane.setOneTouchExpandable(true);
-        setLayout(groupLayout);
-    }
-
-    void divideView() {
-        splitPane.setDividerLocation(.5d);
-    }
-    
-    void hideBottom() {
-        splitPane.getBottomComponent().setMinimumSize(new Dimension(0, 0));
-        splitPane.setDividerLocation(1.0d);
-    }
-    
-    void hideTop() {
-        splitPane.getTopComponent().setMinimumSize(new Dimension(0, 0));
-        splitPane.setDividerLocation(0.0d);
-    }
-    
-    void setTop(JPanel panel) {
-        splitPane.setTopComponent(panel);
-    }
-    
-    void setBottom(JPanel panel) {
-        splitPane.setBottomComponent(panel);
-    }
-}
--- a/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/HeapSwingView.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,236 +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.client.heap.swing;
-
-import java.awt.Component;
-import java.awt.EventQueue;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.List;
-
-import javax.swing.BoxLayout;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.SwingUtilities;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-
-import org.jfree.chart.ChartPanel;
-
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.heap.HeapView;
-import com.redhat.thermostat.client.heap.LocaleResources;
-import com.redhat.thermostat.client.heap.chart.OverviewChart;
-import com.redhat.thermostat.client.swing.SwingComponent;
-import com.redhat.thermostat.client.swing.components.HeaderPanel;
-import com.redhat.thermostat.client.ui.ComponentVisibleListener;
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.redhat.thermostat.common.locale.Translate;
-
-public class HeapSwingView extends HeapView implements SwingComponent {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private StatsPanel stats;
-
-    private HeapPanel heapDetailPanel;
-    private HeaderPanel overview;
-    
-    private JPanel visiblePane;
-    
-    public HeapSwingView() {
-        stats = new StatsPanel();
-        stats.addHeapDumperListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                
-                stats.disableHeapDumperControl();
-                
-                heapDumperNotifier.fireAction(HeapDumperAction.DUMP_REQUESTED);
-            }
-        });
-        
-        stats.addDumpListListener(new ListSelectionListener() {
-            @Override
-            public void valueChanged(ListSelectionEvent arg0) {
-                HeapDump dump = stats.getSelectedHeapDump();
-                heapDumperNotifier.fireAction(HeapDumperAction.ANALYSE, dump);
-            }
-        });
-        
-        visiblePane = new JPanel();
-        visiblePane.setLayout(new BoxLayout(visiblePane, BoxLayout.X_AXIS));
-        
-        heapDetailPanel = new HeapPanel();
-        
-        overview = new HeaderPanel(translator.localize(LocaleResources.HEAP_OVERVIEW_TITLE));
-        overview.setContent(stats);
-        overview.addHierarchyListener(new ViewVisibleListener());
-
-        // at the beginning, only the overview is visible
-        visiblePane.add(overview);
-    }
-    
-    private class ViewVisibleListener extends ComponentVisibleListener {
-        @Override
-        public void componentShown(Component component) {
-            HeapSwingView.this.notify(Action.VISIBLE);
-        }
-
-        @Override
-        public void componentHidden(Component component) {
-            HeapSwingView.this.notify(Action.HIDDEN);
-        }
-    }
-
-    @Override
-    public void setModel(final OverviewChart model) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                ChartPanel charts = new ChartPanel(model.createChart(stats.getWidth(), stats.getBackground()));
-                /*
-                 * By default, ChartPanel scales itself instead of redrawing things when
-                 * it's resized. To have it resize automatically, we need to set minimum
-                 * and maximum sizes. Lets constrain the minimum, but not the maximum
-                 * size.
-                 */
-                final int MINIMUM_DRAW_SIZE = 100;
-
-                charts.setMinimumDrawHeight(MINIMUM_DRAW_SIZE);
-                charts.setMinimumDrawWidth(MINIMUM_DRAW_SIZE);
-
-                charts.setMaximumDrawHeight(Integer.MAX_VALUE);
-                charts.setMaximumDrawWidth(Integer.MAX_VALUE);
-
-                stats.setChartPanel(charts);
-            }
-        });
-    }
-
-    @Override
-    public void updateUsedAndCapacity(final String used, final String capacity) {
-        
-        SwingUtilities.invokeLater(new Runnable() {
-            
-            @Override
-            public void run() {
-                stats.setMax(capacity);
-                stats.setUsed(used);
-            }
-        });
-    }
-
-    @Override
-    public void addHeapDump(final HeapDump dump) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                stats.addDump(dump);
-            }
-        });
-    }
-    
-    @Override
-    public void clearHeapDumpList() {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                stats.clearDumpList();
-            }
-        });
-    }
-    
-    @Override
-    public void openDumpView() {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                visiblePane.removeAll();
-                heapDetailPanel.divideView();
-                heapDetailPanel.setTop(overview);
-
-                visiblePane.add(heapDetailPanel);
-                visiblePane.revalidate();
-            }
-        });
-    }
-
-    @Override
-    public void setChildView(BasicView childView) {
-        if (childView instanceof HeapDetailsSwing) {
-            final HeapDetailsSwing view = (HeapDetailsSwing)childView;
-            SwingUtilities.invokeLater(new Runnable() {
-                @Override
-                public void run() {
-                    heapDetailPanel.setBottom(view.getUiComponent());
-                    visiblePane.revalidate();
-                }
-            });
-        }
-    }
-    
-    @Override
-    public Component getUiComponent() {
-        return visiblePane;
-    }
-
-    @Override
-    public void notifyHeapDumpComplete() {
-        EventQueue.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                stats.enableHeapDumperControl();
-            }
-        });
-    }
-
-    @Override
-    public void updateHeapDumpList(final List<HeapDump> heapDumps) {
-        EventQueue.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                stats.updateHeapDumpList(heapDumps);
-            }
-        });
-    }
-
-    @Override
-    public void displayWarning(String string) {
-        JOptionPane.showMessageDialog(visiblePane, string, "Warning", JOptionPane.WARNING_MESSAGE);
-    }
-}
--- a/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/HistogramPanel.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,176 +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.client.heap.swing;
-
-import java.awt.Component;
-import java.text.DecimalFormat;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.BoxLayout;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.table.DefaultTableModel;
-
-import com.redhat.thermostat.client.heap.HeapHistogramView;
-import com.redhat.thermostat.client.heap.LocaleResources;
-import com.redhat.thermostat.client.swing.SwingComponent;
-import com.redhat.thermostat.client.swing.components.HeaderPanel;
-import com.redhat.thermostat.client.swing.components.ThermostatTable;
-import com.redhat.thermostat.client.swing.components.ThermostatTableRenderer;
-import com.redhat.thermostat.common.heap.HistogramRecord;
-import com.redhat.thermostat.common.heap.ObjectHistogram;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.DescriptorConverter;
-
-@SuppressWarnings("serial")
-public class HistogramPanel extends HeapHistogramView implements SwingComponent {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private final JPanel panel;
-
-    private HeaderPanel headerPanel;
-
-    public HistogramPanel() {
-        panel = new JPanel();
-        panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
-
-        headerPanel = new HeaderPanel(translator.localize(LocaleResources.HEAP_DUMP_CLASS_USAGE));
-        panel.add(headerPanel);
-    }
-
-    @Override
-    public void display(ObjectHistogram histogram) {
-        ThermostatTable table = new ThermostatTable(new HistogramTableModel(histogram));
-        table.setDefaultRenderer(Long.class, new NiceNumberFormatter());
-        headerPanel.setContent(table.wrap());
-    }
-
-    private final class NiceNumberFormatter extends ThermostatTableRenderer {
-
-        private final DecimalFormat formatter = new DecimalFormat("###,###.###");
-
-        private NiceNumberFormatter() {
-            setHorizontalAlignment(JLabel.RIGHT);
-        }
-
-        @Override
-        protected void setValue(Object v) {
-            String formatted = formatter.format(v);
-            setText(formatted);
-        }
-    }
-
-    private class HistogramTableModel extends DefaultTableModel {
-
-        private final String[] columnNames = new String[] {
-            translator.localize(LocaleResources.HEAP_DUMP_HISTOGRAM_COLUMN_CLASS),
-            translator.localize(LocaleResources.HEAP_DUMP_HISTOGRAM_COLUMN_INSTANCES),
-            translator.localize(LocaleResources.HEAP_DUMP_HISTOGRAM_COLUMN_SIZE),
-        };
-
-        private List<HistogramRecord> histogram;
-
-        public HistogramTableModel(ObjectHistogram objHistogram) {
-            histogram = new ArrayList<>();
-            histogram.addAll(objHistogram.getHistogram());
-        }
-
-        @Override
-        public String getColumnName(int column) {
-            return columnNames[column];
-        }
-
-        @Override
-        public Class<?> getColumnClass(int column) {
-            if (column == 0) {
-                return String.class;
-            } else {
-                return Long.class;
-            }
-        }
-
-        @Override
-        public Object getValueAt(int row, int column) {
-            Object result = null;
-            if (row >= histogram.size()) {
-                throw new ArrayIndexOutOfBoundsException();
-            }
-            if (histogram != null) {
-                HistogramRecord record = histogram.get(row);
-                switch (column) {
-                case 0:
-                    result = DescriptorConverter.toJavaType(record.getClassname());
-                    break;
-                case 1:
-                    result = Long.valueOf(record.getNumberOf());
-                    break;
-                case 2:
-                    result = Long.valueOf(record.getTotalSize());
-                    break;
-                default:
-                    throw new ArrayIndexOutOfBoundsException();
-                }
-            }
-            return result;
-        }
-
-        @Override
-        public int getColumnCount() {
-            return 3;
-        }
-
-        @Override
-        public int getRowCount() {
-            if (histogram != null) {
-                return histogram.size();
-            }
-            return 0;
-        }
-
-        @Override
-        public boolean isCellEditable(int row, int column) {
-            return false;
-        }
-    }
-
-    @Override
-    public Component getUiComponent() {
-        return panel;
-    }
-}
--- a/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/LazyMutableTreeNode.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +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.client.heap.swing;
-
-import com.redhat.thermostat.client.heap.HeapObjectUI;
-
-class LazyMutableTreeNode extends javax.swing.tree.DefaultMutableTreeNode {
-
-    public LazyMutableTreeNode() {
-        super();
-    }
-
-    public LazyMutableTreeNode(HeapObjectUI heapObjectUI) {
-        super(heapObjectUI);
-    }
-
-    @Override
-    public boolean isLeaf() {
-        return !getAllowsChildren();
-    }
-}
\ No newline at end of file
--- a/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/ObjectDetailsPanel.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,435 +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.client.heap.swing;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import javax.swing.ButtonGroup;
-import javax.swing.JMenuItem;
-import javax.swing.JPanel;
-import javax.swing.GroupLayout;
-import javax.swing.JPopupMenu;
-import javax.swing.JToggleButton;
-import javax.swing.JTree;
-import javax.swing.SwingUtilities;
-import javax.swing.GroupLayout.Alignment;
-import javax.swing.JLabel;
-
-import com.redhat.thermostat.client.core.views.SearchFieldView.SearchAction;
-import com.redhat.thermostat.client.heap.HeapObjectUI;
-import com.redhat.thermostat.client.heap.LocaleResources;
-import com.redhat.thermostat.client.heap.ObjectDetailsView;
-import com.redhat.thermostat.client.swing.SwingComponent;
-import com.redhat.thermostat.client.swing.components.EdtHelper;
-import com.redhat.thermostat.client.swing.views.SearchFieldSwingView;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionNotifier;
-import com.redhat.thermostat.common.locale.Translate;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-
-import javax.swing.LayoutStyle.ComponentPlacement;
-import javax.swing.JScrollPane;
-import javax.swing.JTextPane;
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-
-import javax.swing.JSplitPane;
-import javax.swing.event.TreeExpansionEvent;
-import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.TreeSelectionListener;
-import javax.swing.event.TreeWillExpandListener;
-import javax.swing.tree.DefaultTreeCellRenderer;
-import javax.swing.tree.DefaultTreeModel;
-import javax.swing.tree.ExpandVetoException;
-import javax.swing.tree.MutableTreeNode;
-import javax.swing.tree.TreePath;
-import javax.swing.tree.TreeSelectionModel;
-
-/**
- * A Panel that displays JavaHeapObjects and referrers and references.
- */
-public class ObjectDetailsPanel extends ObjectDetailsView implements SwingComponent {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    /** For TESTING ONLY! */
-    static final String TREE_NAME = "ref-tree";
-    /** For TESTING ONLY! */
-    static final String DETAILS_NAME = "object-details";
-
-    private final ActionNotifier<ObjectAction> notifier = new ActionNotifier<>(this);
-
-    private final JPanel panel;
-
-    private final SearchFieldSwingView searchField;
-
-    private final LazyMutableTreeNode ROOT = new LazyMutableTreeNode(null);
-    /** all the nodes in this model must be {@link LazyMutableTreeNode}s */
-    private final DefaultTreeModel model = new DefaultTreeModel(ROOT);
-    private final JTree objectTree = new JTree(model);
-
-    private final JTextPane objectDetailsPane;
-
-    private final ButtonGroup refGroup = new ButtonGroup();
-    private final JToggleButton toggleReferrersButton;
-    private final JToggleButton toggleReferencesButton;
-
-    private final List<ObjectReferenceCallback> callbacks = new CopyOnWriteArrayList<>();
-
-    public ObjectDetailsPanel() {
-
-        panel = new JPanel();
-
-        JLabel searchLabel = new JLabel(translator.localize(LocaleResources.HEAP_DUMP_OBJECT_BROWSE_SEARCH_LABEL));
-
-        searchField = new SearchFieldSwingView();
-        searchField.setTooltip(translator.localize(LocaleResources.HEAP_DUMP_OBJECT_BROWSE_SEARCH_PATTERN_HELP));
-
-        JSplitPane splitPane = new JSplitPane();
-        splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
-        splitPane.setDividerLocation(0.8 /* 80% */);
-
-        toggleReferrersButton = new JToggleButton(translator.localize(LocaleResources.HEAP_DUMP_OBJECT_BROWSE_REFERRERS));
-        refGroup.add(toggleReferrersButton);
-
-        toggleReferencesButton = new JToggleButton(translator.localize(LocaleResources.HEAP_DUMP_OBJECT_BROWSE_REFERENCES));
-        refGroup.add(toggleReferencesButton);
-
-        toggleReferrersButton.setSelected(true);
-
-        GroupLayout groupLayout = new GroupLayout(panel);
-        groupLayout.setHorizontalGroup(
-            groupLayout.createParallelGroup(Alignment.LEADING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addContainerGap()
-                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
-                        .addGroup(groupLayout.createSequentialGroup()
-                            .addComponent(searchLabel)
-                            .addPreferredGap(ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                            .addComponent(toggleReferencesButton)
-                            .addPreferredGap(ComponentPlacement.RELATED)
-                            .addComponent(toggleReferrersButton))
-                        .addGroup(groupLayout.createSequentialGroup()
-                            .addGap(12)
-                            .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
-                                .addComponent(splitPane, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 447, Short.MAX_VALUE)
-                                .addComponent(searchField, GroupLayout.DEFAULT_SIZE, 447, Short.MAX_VALUE))))
-                    .addContainerGap())
-        );
-        groupLayout.setVerticalGroup(
-            groupLayout.createParallelGroup(Alignment.LEADING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addContainerGap()
-                    .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
-                        .addComponent(searchLabel)
-                        .addComponent(toggleReferrersButton)
-                        .addComponent(toggleReferencesButton))
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addComponent(searchField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addComponent(splitPane, GroupLayout.DEFAULT_SIZE, 314, Short.MAX_VALUE)
-                    .addContainerGap())
-        );
-
-        searchField.addActionListener(new ActionListener<SearchAction>() {
-            @Override
-            public void actionPerformed(ActionEvent<SearchAction> actionEvent) {
-                switch (actionEvent.getActionId()) {
-                case TEXT_CHANGED:
-                    notifier.fireAction(ObjectAction.SEARCH);
-                    break;
-                }
-            }
-        });
-        searchField.setLabel(translator.localize(LocaleResources.HEAP_DUMP_OBJECT_BROWSE_SEARCH_HINT));
-
-        java.awt.event.ActionListener treeToggleListener = new java.awt.event.ActionListener() {
-            @Override
-            public void actionPerformed(java.awt.event.ActionEvent e) {
-                notifier.fireAction(ObjectAction.SEARCH);
-            }
-        };
-
-        JToggleButton[] buttons = getTreeModeButtons();
-        for (JToggleButton button: buttons) {
-            button.addActionListener(treeToggleListener);
-        }
-
-        JScrollPane scrollPane = new JScrollPane();
-        scrollPane.setViewportView(objectTree);
-
-        splitPane.setLeftComponent(scrollPane);
-
-        JPanel panel = new JPanel();
-        splitPane.setRightComponent(panel);
-
-        panel.setLayout(new BorderLayout(0, 0));
-
-        objectDetailsPane = new JTextPane();
-        objectDetailsPane.setName(DETAILS_NAME);
-        objectDetailsPane.setEditable(false);
-        panel.add(objectDetailsPane);
-        this.panel.setLayout(groupLayout);
-
-        initializeTree();
-        clearTree();
-    }
-
-    private void initializeTree() {
-        objectTree.setName(TREE_NAME);
-        objectTree.setRootVisible(false);
-        objectTree.setShowsRootHandles(true);
-        objectTree.setEditable(false);
-
-        objectTree.addTreeSelectionListener(new TreeSelectionListener() {
-            @Override
-            public void valueChanged(TreeSelectionEvent e) {
-                notifier.fireAction(ObjectAction.GET_OBJECT_DETAIL);
-            }
-        });
-
-        if (objectTree.getCellRenderer() instanceof DefaultTreeCellRenderer) {
-            DefaultTreeCellRenderer cellRenderer = (DefaultTreeCellRenderer) objectTree.getCellRenderer();
-            cellRenderer.setClosedIcon(null);
-            cellRenderer.setOpenIcon(null);
-            cellRenderer.setLeafIcon(null);
-        }
-
-        objectTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
-        objectTree.expandPath(new TreePath(ROOT.getPath()));
-
-        objectTree.addTreeWillExpandListener(new TreeWillExpandListener() {
-
-            @Override
-            public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
-                if (new TreePath(ROOT.getPath()).equals(event.getPath())) {
-                    return;
-                }
-
-                lazyLoadChildren(event.getPath());
-            }
-
-            @Override
-            public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
-                if (new TreePath(ROOT.getPath()).equals(event.getPath())) {
-                    throw new ExpandVetoException(event, "root cant be collapsed");
-                }
-            }
-        });
-
-        objectTree.addMouseListener(new MouseAdapter() {
-            @Override
-            public void mousePressed(MouseEvent e) {
-                if (e.isPopupTrigger()) {
-                    int row = objectTree.getRowForLocation(e.getX(), e.getY());
-                    if (row == -1) {
-                        return;
-                    }
-
-                    TreePath path = objectTree.getPathForRow(row);
-                    final HeapObjectUI heapObject = (HeapObjectUI) ((LazyMutableTreeNode)path.getLastPathComponent()).getUserObject();
-                    JPopupMenu popup = new JPopupMenu();
-                    JMenuItem findRootItem = new JMenuItem(translator.localize(LocaleResources.HEAP_DUMP_OBJECT_FIND_ROOT));
-                    findRootItem.addActionListener(new java.awt.event.ActionListener() {
-                        @Override
-                        public void actionPerformed(java.awt.event.ActionEvent e) {
-                            notifier.fireAction(ObjectAction.SHOW_ROOT_TO_GC, heapObject);
-                        }
-                    });
-                    popup.add(findRootItem);
-                    popup.show(e.getComponent(), e.getX(), e.getY());
-                }
-            }
-        });
-    }
-
-    private void clearTree() {
-        // clear children from model
-        int childrenCount = ROOT.getChildCount();
-        for (int i = 0; i < childrenCount; i++) {
-            MutableTreeNode child = (MutableTreeNode) ROOT.getChildAt(0);
-            model.removeNodeFromParent(child);
-        }
-    }
-
-    private void lazyLoadChildren(TreePath path) {
-        LazyMutableTreeNode node = (LazyMutableTreeNode) path.getLastPathComponent();
-        if (node.getChildCount() > 0) {
-            // already processed
-            return;
-        }
-
-        if (toggleReferencesButton.isSelected()) {
-            addReferences(node);
-        } else if (toggleReferrersButton.isSelected()) {
-            addReferrers(node);
-        }
-    }
-
-    private void addReferrers(LazyMutableTreeNode node) {
-        HeapObjectUI data = (HeapObjectUI) node.getUserObject();
-
-        List<HeapObjectUI> referrers = new ArrayList<>();
-        for (ObjectReferenceCallback callback : callbacks) {
-            referrers.addAll(callback.getReferrers(data));
-        }
-
-        for (HeapObjectUI obj: referrers) {
-            model.insertNodeInto(new LazyMutableTreeNode(obj), node, node.getChildCount());
-        }
-    }
-
-    private void addReferences(LazyMutableTreeNode node) {
-        HeapObjectUI data = (HeapObjectUI) node.getUserObject();
-
-        List<HeapObjectUI> referrers = new ArrayList<>();
-        for (ObjectReferenceCallback callback : callbacks) {
-            referrers.addAll(callback.getReferences(data));
-        }
-
-        for (HeapObjectUI obj: referrers) {
-            model.insertNodeInto(new LazyMutableTreeNode(obj), node, node.getChildCount());
-        }
-    }
-
-    private JToggleButton[] getTreeModeButtons() {
-        return new JToggleButton[] { toggleReferencesButton, toggleReferrersButton };
-    }
-
-    @Override
-    public void addObjectActionListener(ActionListener<ObjectAction> listener) {
-        notifier.addActionListener(listener);
-    }
-
-    @Override
-    public void removeObjectActionListnener(ActionListener<ObjectAction> listener) {
-        notifier.removeActionListener(listener);
-    }
-
-    @Override
-    public void addObjectReferenceCallback(ObjectReferenceCallback callback) {
-        callbacks.add(callback);
-    }
-
-    @Override
-    public void removeObjectReferenceCallback(ObjectReferenceCallback callback) {
-        callbacks.remove(callback);
-    }
-
-    @Override
-    public String getSearchText() {
-        try {
-            return new EdtHelper().callAndWait(new Callable<String>() {
-                @Override
-                public String call() throws Exception {
-                    return searchField.getSearchText();
-                }
-            });
-        } catch (InvocationTargetException | InterruptedException e) {
-            e.printStackTrace();
-            return null;
-        }
-    }
-
-    @Override
-    public void setMatchingObjects(final Collection<HeapObjectUI> objects) {
-        try {
-            new EdtHelper().callAndWait(new Runnable() {
-                @Override
-                public void run() {
-                    // clear children
-                    clearTree();
-
-                    // add new children
-                    for (HeapObjectUI object: objects) {
-                        MutableTreeNode node = new LazyMutableTreeNode(object);
-                        model.insertNodeInto(node, ROOT, ROOT.getChildCount());
-                    }
-                    objectTree.expandPath(new TreePath(ROOT.getPath()));
-                }
-            });
-        } catch (InvocationTargetException | InterruptedException e) {
-            e.printStackTrace();
-        }
-    }
-
-    @Override
-    public void setObjectDetails(final JavaHeapObject obj) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                // TODO use some other gui control for this rather than a plain text box
-                String text = translator.localize(LocaleResources.COMMAND_OBJECT_INFO_OBJECT_ID) + obj.getIdString() + "\n" +
-                              translator.localize(LocaleResources.COMMAND_OBJECT_INFO_TYPE) + obj.getClazz().getName() + "\n" +
-                              translator.localize(LocaleResources.COMMAND_OBJECT_INFO_SIZE) + String.valueOf(obj.getSize()) + " bytes" + "\n" +
-                              translator.localize(LocaleResources.COMMAND_OBJECT_INFO_HEAP_ALLOCATED) + String.valueOf(obj.isHeapAllocated()) + "\n";
-                objectDetailsPane.setText(text);
-            }
-        });
-    }
-
-    /**
-     * @return null if no selected object
-     */
-    @Override
-    public HeapObjectUI getSelectedMatchingObject() {
-        try {
-            return new EdtHelper().callAndWait(new Callable<HeapObjectUI>() {
-                @Override
-                public HeapObjectUI call() throws Exception {
-                    LazyMutableTreeNode node = (LazyMutableTreeNode) objectTree.getSelectionPath().getLastPathComponent();
-                    return (HeapObjectUI) node.getUserObject();
-                }
-            });
-        } catch (InvocationTargetException | InterruptedException e) {
-            return null;
-        }
-    }
-
-    @Override
-    public Component getUiComponent() {
-        return panel;
-    }
-}
--- a/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/ObjectRootsFrame.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,241 +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.client.heap.swing;
-
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Callable;
-
-import javax.swing.GroupLayout;
-import javax.swing.GroupLayout.Alignment;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JScrollPane;
-import javax.swing.JTextPane;
-import javax.swing.JTree;
-import javax.swing.LayoutStyle.ComponentPlacement;
-import javax.swing.SwingUtilities;
-import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.TreeSelectionListener;
-import javax.swing.tree.DefaultTreeModel;
-import javax.swing.tree.MutableTreeNode;
-import javax.swing.tree.TreePath;
-
-import com.redhat.thermostat.client.heap.HeapObjectUI;
-import com.redhat.thermostat.client.heap.LocaleResources;
-import com.redhat.thermostat.client.heap.ObjectRootsView;
-import com.redhat.thermostat.client.swing.components.EdtHelper;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.ActionNotifier;
-import com.redhat.thermostat.common.locale.Translate;
-
-@SuppressWarnings("serial")
-public class ObjectRootsFrame extends JFrame implements ObjectRootsView {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    /** For TESTING ONLY! */
-    static final String TREE_NAME = "roots-tree";
-
-    static final String DETAILS_NAME = "object-details";
-
-    private final ActionNotifier<Action> notifier = new ActionNotifier<>(this);
-
-    private final LazyMutableTreeNode ROOT = new LazyMutableTreeNode();
-    private final DefaultTreeModel dataModel;
-    private final JTree pathToRootTree;
-
-    private final JTextPane objectDetails;
-
-    public ObjectRootsFrame() {
-        setTitle(translator.localize(LocaleResources.OBJECT_ROOTS_VIEW_TITLE));
-
-        dataModel = new DefaultTreeModel(ROOT);
-        pathToRootTree = new JTree(dataModel);
-        pathToRootTree.setName(TREE_NAME);
-
-        JLabel lblNewLabel = new JLabel(translator.localize(LocaleResources.OBJECT_ROOTS_VIEW_TITLE));
-
-        JScrollPane scrollPane = new JScrollPane(pathToRootTree);
-
-        objectDetails = new JTextPane();
-        objectDetails.setName(DETAILS_NAME);
-
-        GroupLayout groupLayout = new GroupLayout(getContentPane());
-        groupLayout.setHorizontalGroup(
-            groupLayout.createParallelGroup(Alignment.TRAILING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addContainerGap()
-                    .addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
-                        .addComponent(scrollPane, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 416, Short.MAX_VALUE)
-                        .addComponent(objectDetails, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 416, Short.MAX_VALUE)
-                        .addComponent(lblNewLabel, Alignment.LEADING))
-                    .addContainerGap())
-        );
-        groupLayout.setVerticalGroup(
-            groupLayout.createParallelGroup(Alignment.LEADING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addContainerGap()
-                    .addComponent(lblNewLabel)
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 126, Short.MAX_VALUE)
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addComponent(objectDetails, GroupLayout.PREFERRED_SIZE, 93, GroupLayout.PREFERRED_SIZE)
-                    .addContainerGap())
-        );
-        getContentPane().setLayout(groupLayout);
-
-        addWindowListener(new WindowAdapter() {
-            @Override
-            public void windowOpened(WindowEvent e) {
-                notifier.fireAction(Action.VISIBLE);
-            }
-
-            @Override
-            public void windowClosing(WindowEvent e) {
-                notifier.fireAction(Action.HIDDEN);
-            }
-        });
-
-        pathToRootTree.addTreeSelectionListener(new TreeSelectionListener() {
-            @Override
-            public void valueChanged(TreeSelectionEvent e) {
-                HeapObjectUI obj = (HeapObjectUI) ((LazyMutableTreeNode)e.getPath().getLastPathComponent()).getUserObject();
-                notifier.fireAction(Action.OBJECT_SELECTED, obj);
-            }
-        });
-
-
-    }
-
-    @Override
-    public void addActionListener(ActionListener<Action> listener) {
-        notifier.addActionListener(listener);
-    }
-
-    @Override
-    public void removeActionListener(ActionListener<Action> listener) {
-        notifier.removeActionListener(listener);
-    }
-
-    @Override
-    public void showView() {
-        Callable<Boolean> hideViewRunnable = new Callable<Boolean>() {
-            @Override
-            public Boolean call() {
-                pack();
-                setVisible(true);
-                return new Boolean(true);
-            }
-        };
-        try {
-            new EdtHelper().callAndWait(hideViewRunnable);
-        } catch (InvocationTargetException | InterruptedException e) {
-            InternalError error = new InternalError();
-            error.initCause(e);
-            throw error;
-        }
-    }
-
-    @Override
-    public void hideView() {
-        Callable<Boolean> hideViewRunnable = new Callable<Boolean>() {
-            @Override
-            public Boolean call() {
-                setVisible(false);
-                dispose();
-                return new Boolean(true);
-            }
-        };
-        try {
-            new EdtHelper().callAndWait(hideViewRunnable);
-        } catch (InvocationTargetException | InterruptedException e) {
-            InternalError error = new InternalError();
-            error.initCause(e);
-            throw error;
-        }
-    }
-
-    @Override
-    public void setPathToRoot(List<HeapObjectUI> pathToRoot) {
-        final List<HeapObjectUI> path = new ArrayList<>(pathToRoot);
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                clearTree();
-
-                LazyMutableTreeNode node = ROOT;
-                node.setUserObject(path.get(0));
-                TreePath treePath = new TreePath(node);
-                LazyMutableTreeNode parent = ROOT;
-                for (int i = 1; i < path.size(); i++) {
-                    HeapObjectUI obj = path.get(i);
-                    node = new LazyMutableTreeNode(obj);
-                    dataModel.insertNodeInto(node, parent, node.getChildCount());
-                    parent = node;
-                    treePath = treePath.pathByAddingChild(node);
-                }
-
-                pathToRootTree.expandPath(treePath);
-                pathToRootTree.setSelectionPath(treePath);
-            }
-        });
-    }
-
-    private void clearTree() {
-        // clear children from model
-        int childrenCount = ROOT.getChildCount();
-        for (int i = 0; i < childrenCount; i++) {
-            MutableTreeNode child = (MutableTreeNode) ROOT.getChildAt(0);
-            dataModel.removeNodeFromParent(child);
-        }
-    }
-
-    @Override
-    public void setObjectDetails(final String information) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                objectDetails.setText(information);
-            }
-        });
-    }
-
-}
--- a/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/StatsPanel.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,210 +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.client.heap.swing;
-
-import java.awt.event.ActionListener;
-import java.util.List;
-
-import javax.swing.BoxLayout;
-import javax.swing.DefaultListModel;
-import javax.swing.GroupLayout;
-import javax.swing.GroupLayout.Alignment;
-import javax.swing.JButton;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.LayoutStyle.ComponentPlacement;
-import javax.swing.ListSelectionModel;
-import javax.swing.SwingConstants;
-import javax.swing.event.ListSelectionListener;
-
-import com.redhat.thermostat.common.heap.HeapDump;
-
-@SuppressWarnings("serial")
-public class StatsPanel extends JPanel {
-    
-    private JPanel leftPanel;
-    
-    private JButton heapDumpButton;
-    private JList<HeapDump> dumpList;
-    private DefaultListModel<HeapDump> listModel;
-    
-    private JLabel max;
-    private JLabel current;
-    
-    public StatsPanel() {
-        
-        leftPanel = new JPanel();
-        leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.X_AXIS));
-        
-        JPanel rightPanel = new JPanel();
-        GroupLayout groupLayout = new GroupLayout(this);
-        groupLayout.setHorizontalGroup(
-            groupLayout.createParallelGroup(Alignment.LEADING)
-                .addGroup(Alignment.TRAILING, groupLayout.createSequentialGroup()
-                    .addComponent(leftPanel, GroupLayout.DEFAULT_SIZE, 343, Short.MAX_VALUE)
-                    .addPreferredGap(ComponentPlacement.UNRELATED)
-                    .addComponent(rightPanel, GroupLayout.PREFERRED_SIZE, 252, GroupLayout.PREFERRED_SIZE))
-        );
-        groupLayout.setVerticalGroup(
-            groupLayout.createParallelGroup(Alignment.LEADING)
-                .addComponent(rightPanel, GroupLayout.DEFAULT_SIZE, 293, Short.MAX_VALUE)
-                .addComponent(leftPanel, GroupLayout.DEFAULT_SIZE, 293, Short.MAX_VALUE)
-        );
-        
-        JLabel currentLabel = new JLabel("used:");
-        currentLabel.setHorizontalAlignment(SwingConstants.LEFT);
-        
-        JLabel maxLabel = new JLabel("capacity:");
-        maxLabel.setHorizontalAlignment(SwingConstants.LEFT);
-        
-        current = new JLabel("-");
-        current.setHorizontalAlignment(SwingConstants.RIGHT);
-        
-        max = new JLabel("-");
-        max.setHorizontalAlignment(SwingConstants.RIGHT);
-        
-        heapDumpButton = new JButton("Heap Dump");
-        heapDumpButton.setName("heapDumpButton");
-
-        JScrollPane dumpListScrollPane = new JScrollPane();
-        dumpList = new JList<>();
-        dumpList.setName("heapDumpList");
-        listModel = new DefaultListModel<>();
-        dumpList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-        dumpList.setModel(listModel);
-        
-        GroupLayout gl_rightPanel = new GroupLayout(rightPanel);
-        gl_rightPanel.setHorizontalGroup(
-            gl_rightPanel.createParallelGroup(Alignment.TRAILING)
-                .addGroup(gl_rightPanel.createSequentialGroup()
-                    .addContainerGap()
-                    .addGroup(gl_rightPanel.createParallelGroup(Alignment.TRAILING)
-                        .addComponent(dumpListScrollPane, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 173, Short.MAX_VALUE)
-                        .addComponent(heapDumpButton, GroupLayout.DEFAULT_SIZE, 173, Short.MAX_VALUE)
-                        .addGroup(gl_rightPanel.createSequentialGroup()
-                            .addGroup(gl_rightPanel.createParallelGroup(Alignment.TRAILING, false)
-                                .addComponent(maxLabel, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                                .addComponent(currentLabel, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 48, Short.MAX_VALUE))
-                            .addPreferredGap(ComponentPlacement.RELATED)
-                            .addGroup(gl_rightPanel.createParallelGroup(Alignment.TRAILING)
-                                .addComponent(current, GroupLayout.DEFAULT_SIZE, 119, Short.MAX_VALUE)
-                                .addComponent(max, GroupLayout.PREFERRED_SIZE, 119, GroupLayout.PREFERRED_SIZE))))
-                    .addContainerGap())
-        );
-        gl_rightPanel.setVerticalGroup(
-            gl_rightPanel.createParallelGroup(Alignment.LEADING)
-                .addGroup(gl_rightPanel.createSequentialGroup()
-                    .addContainerGap()
-                    .addGroup(gl_rightPanel.createParallelGroup(Alignment.BASELINE)
-                        .addComponent(currentLabel, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE)
-                        .addComponent(current))
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addGroup(gl_rightPanel.createParallelGroup(Alignment.BASELINE)
-                        .addComponent(maxLabel)
-                        .addComponent(max))
-                    .addGap(18)
-                    .addComponent(heapDumpButton)
-                    .addGap(18)
-                    .addComponent(dumpListScrollPane, GroupLayout.DEFAULT_SIZE, 172, Short.MAX_VALUE)
-                    .addContainerGap())
-        );
-        rightPanel.setLayout(gl_rightPanel);
-        setLayout(groupLayout);
-
-        dumpListScrollPane.setViewportView(dumpList);
-    }
-    
-    void setChartPanel(JPanel panel) {
-        leftPanel.removeAll();
-        leftPanel.add(panel);
-        leftPanel.revalidate();
-        repaint();
-    }
-
-    public void setMax(String capacity) {
-        max.setText(capacity);
-    }
-
-    public void setUsed(String used) {
-        current.setText(used);
-    }
-    
-    void addHeapDumperListener(ActionListener listener) {
-        heapDumpButton.addActionListener(listener);
-    }
-
-    void addDumpListListener(ListSelectionListener listener) {
-        dumpList.addListSelectionListener(listener);
-    }
-    
-    public void disableHeapDumperControl() {
-        heapDumpButton.setText("dumping...");
-        heapDumpButton.setEnabled(false);
-    }
-
-    public void enableHeapDumperControl() {
-        heapDumpButton.setText("Heap Dump");
-        heapDumpButton.setEnabled(true);
-    }
-
-    public void addDump(HeapDump dump) {
-        
-        listModel.addElement(dump);
-    }
-
-    public void clearDumpList() {
-        listModel.clear();
-    }
-    
-    public HeapDump getSelectedHeapDump() {
-        return dumpList.getSelectedValue();
-    }
-
-    public void updateHeapDumpList(List<HeapDump> heapDumps) {
-        int numItemsBefore = listModel.getSize();
-        for (HeapDump heapDump : heapDumps) {
-            if (! listModel.contains(heapDump)) {
-                listModel.addElement(heapDump);
-            }
-        }
-        if (numItemsBefore == 0 && listModel.getSize() > 0) {
-            dumpList.repaint();
-        }
-    }
-}
--- a/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/SwingHeapDumpDetailsViewProvider.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +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.client.heap.swing;
-
-import com.redhat.thermostat.client.heap.HeapDumpDetailsView;
-import com.redhat.thermostat.client.heap.HeapDumpDetailsViewProvider;
-
-public class SwingHeapDumpDetailsViewProvider implements
-        HeapDumpDetailsViewProvider {
-
-    @Override
-    public HeapDumpDetailsView createView() {
-        return new HeapDetailsSwing();
-    }
-
-}
--- a/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/SwingHeapHistogramViewProvider.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +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.client.heap.swing;
-
-import com.redhat.thermostat.client.heap.HeapHistogramView;
-import com.redhat.thermostat.client.heap.HeapHistogramViewProvider;
-
-public class SwingHeapHistogramViewProvider implements
-        HeapHistogramViewProvider {
-
-    @Override
-    public HeapHistogramView createView() {
-        return new HistogramPanel();
-    }
-
-}
--- a/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/SwingHeapViewProvider.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +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.client.heap.swing;
-
-import com.redhat.thermostat.client.heap.HeapView;
-import com.redhat.thermostat.client.heap.HeapViewProvider;
-
-public class SwingHeapViewProvider implements HeapViewProvider {
-
-    @Override
-    public HeapView createView() {
-        return new HeapSwingView();
-    }
-
-}
--- a/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/SwingObjectDetailsViewProvider.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +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.client.heap.swing;
-
-import com.redhat.thermostat.client.heap.ObjectDetailsView;
-import com.redhat.thermostat.client.heap.ObjectDetailsViewProvider;
-
-public class SwingObjectDetailsViewProvider implements
-        ObjectDetailsViewProvider {
-
-    @Override
-    public ObjectDetailsView createView() {
-        return new ObjectDetailsPanel();
-    }
-
-}
--- a/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/SwingObjectRootsViewProvider.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +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.client.heap.swing;
-
-import com.redhat.thermostat.client.heap.ObjectRootsView;
-import com.redhat.thermostat.client.heap.ObjectRootsViewProvider;
-
-public class SwingObjectRootsViewProvider implements ObjectRootsViewProvider {
-
-    @Override
-    public ObjectRootsView createView() {
-        return new ObjectRootsFrame();
-    }
-
-}
--- a/client/heapdumper/swing/src/test/java/com/redhat/thermostat/client/heap/swing/HeapDetailsSwingTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,151 +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.client.heap.swing;
-
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.concurrent.Callable;
-
-import javax.swing.JFrame;
-import javax.swing.JPanel;
-
-import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
-
-import org.fest.swing.annotation.GUITest;
-import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
-import org.fest.swing.edt.GuiActionRunner;
-import org.fest.swing.edt.GuiTask;
-import org.fest.swing.fixture.FrameFixture;
-import org.fest.swing.fixture.JTabbedPaneFixture;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import com.redhat.thermostat.client.swing.components.EdtHelper;
-
-@RunWith(CacioFESTRunner.class)
-public class HeapDetailsSwingTest {
-
-    private JFrame frame;
-    private FrameFixture frameFixture;
-    private HeapDetailsSwing view;
-
-    @BeforeClass
-    public static void setUpOnce() {
-        FailOnThreadViolationRepaintManager.install();
-    }
-
-    @Before
-    public void setUp() {
-        GuiActionRunner.execute(new GuiTask() {
-            @Override
-            protected void executeInEDT() throws Throwable {
-                view = new HeapDetailsSwing();
-                frame = new JFrame();
-                frame.add(view.getUiComponent());
-
-            }
-        });
-        frameFixture = new FrameFixture(frame);
-    }
-
-    @After
-    public void tearDown() {
-        frameFixture.cleanUp();
-        frameFixture = null;
-    }
-
-    @GUITest
-    @Test
-    public void verifyTabsAdded() throws InvocationTargetException, InterruptedException {
-        frameFixture.show();
-
-        JTabbedPaneFixture tabPane = frameFixture.tabbedPane("tabs");
-        assertNotNull(tabPane);
-
-        HistogramPanel histogramView = mock(HistogramPanel.class);
-        when(histogramView.getUiComponent()).thenReturn(new EdtHelper().callAndWait(new Callable<JPanel>() {
-            @Override
-            public JPanel call() throws Exception {
-                return new JPanel();
-            }
-        }));
-
-        ObjectDetailsPanel objectDetailsView = mock(ObjectDetailsPanel.class);
-        when(objectDetailsView.getUiComponent()).thenReturn(new EdtHelper().callAndWait(new Callable<JPanel>() {
-            @Override
-            public JPanel call() throws Exception {
-                return new JPanel();
-            }
-        }));
-        view.addSubView("test1", histogramView);
-        view.addSubView("test2", objectDetailsView);
-
-        tabPane.requireTabTitles("test1", "test2");
-    }
-
-
-    @GUITest
-    @Test
-    public void verifyAddRemove() throws InvocationTargetException, InterruptedException {
-        frameFixture.show();
-
-        JTabbedPaneFixture tabPane = frameFixture.tabbedPane("tabs");
-        assertNotNull(tabPane);
-
-        HistogramPanel histogramView = mock(HistogramPanel.class);
-        when(histogramView.getUiComponent()).thenReturn(new EdtHelper().callAndWait(new Callable<JPanel>() {
-            @Override
-            public JPanel call() throws Exception {
-                return new JPanel();
-            }
-        }));
-
-        view.addSubView("test1", histogramView);
-
-        tabPane.requireTabTitles("test1");
-
-        view.removeSubView("test1");
-
-        tabPane.requireTabTitles();
-    }
-}
--- a/client/heapdumper/swing/src/test/java/com/redhat/thermostat/client/heap/swing/HeapSwingViewTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,146 +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.client.heap.swing;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import java.awt.Container;
-import java.util.Arrays;
-import java.util.List;
-
-import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
-
-import org.fest.swing.annotation.GUITest;
-import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
-import org.fest.swing.edt.GuiActionRunner;
-import org.fest.swing.edt.GuiTask;
-import org.fest.swing.fixture.Containers;
-import org.fest.swing.fixture.FrameFixture;
-import org.fest.swing.fixture.JButtonFixture;
-import org.fest.swing.fixture.JListFixture;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import com.redhat.thermostat.client.heap.HeapView.HeapDumperAction;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.heap.HeapDump;
-
-@RunWith(CacioFESTRunner.class)
-public class HeapSwingViewTest {
-
-    private HeapSwingView view;
-
-    private FrameFixture frame;
-
-    @BeforeClass
-    public static void setUpOnce() {
-        FailOnThreadViolationRepaintManager.install();
-    }
-
-
-    @Before
-    public void setUp() throws Exception {
-        GuiActionRunner.execute(new GuiTask() {
-            
-            @Override
-            protected void executeInEDT() throws Throwable {
-                view = new HeapSwingView();
-            }
-        });
-        frame = Containers.showInFrame((Container) view.getUiComponent());
-    }
-
-    @After
-    public void tearDown() {
-        frame.cleanUp();
-        frame = null;
-        view = null;
-    }
-
-    @Test
-    @GUITest
-    public void testActivateHeapDump() {
-        @SuppressWarnings("unchecked")
-        ActionListener<HeapDumperAction> l = mock(ActionListener.class);
-        view.addDumperListener(l);
-        JButtonFixture heapDumpButton = frame.button("heapDumpButton");
-        heapDumpButton.click();
-        verify(l).actionPerformed(new ActionEvent<HeapDumperAction>(view, HeapDumperAction.DUMP_REQUESTED));
-    }
-
-    @Test
-    @GUITest
-    public void testNotifyHeapDumpComplete() {
-        final JButtonFixture heapDumpButton = frame.button("heapDumpButton");
-        GuiActionRunner.execute(new GuiTask() {
-            
-            @Override
-            protected void executeInEDT() throws Throwable {
-                heapDumpButton.component().setEnabled(false);
-            }
-        });
-
-        view.notifyHeapDumpComplete();
-        frame.robot.waitForIdle();
-
-        heapDumpButton.requireEnabled();
-    }
-
-    @Test
-    @GUITest
-    public void testUpdateHeapDumpList() {
-        JListFixture heapDumpList = frame.list("heapDumpList");
-        heapDumpList.requireItemCount(0);
-
-        HeapDump heapDump = mock(HeapDump.class);
-        List<HeapDump> heapDumps = Arrays.asList(heapDump);
-
-        view.updateHeapDumpList(heapDumps);
-        frame.robot.waitForIdle();
-        heapDumpList.requireItemCount(1);
-
-        view.updateHeapDumpList(heapDumps);
-        frame.robot.waitForIdle();
-        heapDumpList.requireItemCount(1);
-
-    }
-}
--- a/client/heapdumper/swing/src/test/java/com/redhat/thermostat/client/heap/swing/ObjectDetailsPanelTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,189 +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.client.heap.swing;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.swing.JFrame;
-import javax.swing.JTree;
-import javax.swing.tree.DefaultMutableTreeNode;
-import javax.swing.tree.TreePath;
-
-import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
-
-import org.fest.swing.annotation.GUITest;
-import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
-import org.fest.swing.edt.GuiActionRunner;
-import org.fest.swing.edt.GuiTask;
-import org.fest.swing.fixture.FrameFixture;
-import org.fest.swing.fixture.JTextComponentFixture;
-import org.fest.swing.fixture.JTreeFixture;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import com.redhat.thermostat.client.core.views.SearchFieldView;
-import com.redhat.thermostat.client.heap.HeapObjectUI;
-import com.redhat.thermostat.client.heap.ObjectDetailsView.ObjectAction;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.sun.tools.hat.internal.model.JavaClass;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-
-@RunWith(CacioFESTRunner.class)
-public class ObjectDetailsPanelTest {
-
-    private JFrame frame;
-    private FrameFixture frameFixture;
-    private ObjectDetailsPanel view;
-    private ActionListener<ObjectAction> listener;
-
-    @BeforeClass
-    public static void setUpOnce() {
-        FailOnThreadViolationRepaintManager.install();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Before
-    public void setUp() {
-        GuiActionRunner.execute(new GuiTask() {
-            @Override
-            protected void executeInEDT() throws Throwable {
-                view = new ObjectDetailsPanel();
-                frame = new JFrame();
-                frame.add(view.getUiComponent());
-
-            }
-        });
-        frameFixture = new FrameFixture(frame);
-
-        listener = mock(ActionListener.class);
-        view.addObjectActionListener(listener);
-    }
-
-    @After
-    public void tearDown() {
-        frameFixture.cleanUp();
-        frameFixture = null;
-    }
-
-    @GUITest
-    @Test
-    public void verifySearchWorks() {
-        final String SEARCH_TEXT = "test";
-
-        frameFixture.show();
-
-        JTextComponentFixture searchBox = frameFixture.textBox(SearchFieldView.VIEW_NAME);
-        searchBox.enterText(SEARCH_TEXT);
-
-        verify(listener, times(SEARCH_TEXT.length())).actionPerformed(new ActionEvent<ObjectAction>(view, ObjectAction.SEARCH));
-
-        assertEquals(SEARCH_TEXT, view.getSearchText());
-    }
-
-    @GUITest
-    @Test
-    public void verifyMatchingObjectsWork() {
-        frameFixture.show();
-
-        HeapObjectUI obj1 = new HeapObjectUI("obj1", "obj1");
-        HeapObjectUI obj2 = new HeapObjectUI("obj2", "obj2");
-
-        view.setMatchingObjects(Arrays.asList(obj1, obj2));
-
-        JTreeFixture tree = frameFixture.tree(ObjectDetailsPanel.TREE_NAME);
-
-        TreePath[] paths = getRows(tree.component());
-
-        assertEquals(obj1, getUserObject(paths[0]));
-        assertEquals(obj2, getUserObject(paths[1]));
-
-        tree.selectPath("obj1");
-
-        assertEquals(obj1, view.getSelectedMatchingObject());
-    }
-
-    private static Object getUserObject(TreePath path) {
-        return ((DefaultMutableTreeNode)path.getLastPathComponent()).getUserObject();
-    }
-
-    private static TreePath[] getRows(JTree tree) {
-        List<TreePath> paths = new ArrayList<>();
-        for (int i = 0; i < tree.getRowCount(); i++) {
-            paths.add(tree.getPathForRow(i));
-        }
-        return paths.toArray(new TreePath[0]);
-    }
-
-    @GUITest
-    @Test
-    public void verifySettingObjectDetails() {
-        final String OBJECT_ID = "id";
-        final boolean HEAP_ALLOCATED = true;
-        final int OBJECT_SIZE = 10;
-        final String OBJECT_CLASS = "foo.bar.Baz";
-
-        frameFixture.show();
-
-        JavaClass klass = mock(JavaClass.class);
-        when(klass.getName()).thenReturn(OBJECT_CLASS);
-
-        JavaHeapObject heapObj = mock(JavaHeapObject.class);
-        when(heapObj.getIdString()).thenReturn(OBJECT_ID);
-        when(heapObj.isHeapAllocated()).thenReturn(HEAP_ALLOCATED);
-        when(heapObj.getSize()).thenReturn(OBJECT_SIZE);
-        when(heapObj.getClazz()).thenReturn(klass);
-
-        view.setObjectDetails(heapObj);
-
-        JTextComponentFixture textBox = frameFixture.textBox(ObjectDetailsPanel.DETAILS_NAME);
-        String expected = "Object ID:" + OBJECT_ID  + "\nType:" + OBJECT_CLASS + "\nSize:" + OBJECT_SIZE + " bytes\nHeap allocated:" + HEAP_ALLOCATED + "\n";
-        assertEquals(expected, textBox.text());
-    }
-
-}
--- a/client/heapdumper/swing/src/test/java/com/redhat/thermostat/client/heap/swing/ObjectRootsFrameTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,190 +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.client.heap.swing;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.JTree;
-import javax.swing.tree.DefaultMutableTreeNode;
-import javax.swing.tree.TreePath;
-
-import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
-
-import org.fest.swing.annotation.GUITest;
-import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
-import org.fest.swing.edt.GuiActionRunner;
-import org.fest.swing.edt.GuiQuery;
-import org.fest.swing.fixture.FrameFixture;
-import org.fest.swing.fixture.JTextComponentFixture;
-import org.fest.swing.fixture.JTreeFixture;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-
-import com.redhat.thermostat.client.heap.HeapObjectUI;
-import com.redhat.thermostat.client.heap.ObjectRootsView;
-import com.redhat.thermostat.client.heap.ObjectRootsView.Action;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-
-@RunWith(CacioFESTRunner.class)
-public class ObjectRootsFrameTest {
-
-    private ObjectRootsFrame frame;
-    private FrameFixture frameFixture;
-
-    @BeforeClass
-    public static void setUpOnce() {
-        FailOnThreadViolationRepaintManager.install();
-    }
-
-    @Before
-    public void setUp() {
-        frame = GuiActionRunner.execute(new GuiQuery<ObjectRootsFrame>() {
-            @Override
-            protected ObjectRootsFrame executeInEDT() throws Throwable {
-                return new ObjectRootsFrame();
-            }
-        });
-        frameFixture = new FrameFixture(frame);
-    }
-
-    @After
-    public void tearDown() {
-        frameFixture.cleanUp();
-        frameFixture = null;
-        frame.hideView();
-    }
-
-    @GUITest
-    @Test
-    public void verifyShowHide() {
-        frame.showView();
-
-        frameFixture.requireVisible();
-
-        frame.hideView();
-
-        frameFixture.requireNotVisible();
-    }
-
-    @GUITest
-    @Test
-    public void verifySetPath() {
-        List<HeapObjectUI> path = new ArrayList<>();
-        path.add(new HeapObjectUI("test", "test"));
-        path.add(new HeapObjectUI("test2", "test2"));
-        frame.setPathToRoot(path);
-
-        frame.showView();
-
-        frameFixture.requireVisible();
-
-        JTreeFixture tree = frameFixture.tree(ObjectRootsFrame.TREE_NAME);
-
-        TreePath[] paths = getRows(tree.component());
-
-        assertEquals(path.get(0), getUserObject(paths[0]));
-        assertEquals(path.get(1), getUserObject(paths[1]));
-    }
-
-    private static Object getUserObject(TreePath path) {
-        return ((DefaultMutableTreeNode)path.getLastPathComponent()).getUserObject();
-    }
-
-    private static TreePath[] getRows(JTree tree) {
-        List<TreePath> paths = new ArrayList<>();
-        for (int i = 0; i < tree.getRowCount(); i++) {
-            paths.add(tree.getPathForRow(i));
-        }
-        return paths.toArray(new TreePath[0]);
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @GUITest
-    @Test
-    public void verifyTreeInteraction() {
-        frame.showView();
-
-        frameFixture.requireVisible();
-
-        ActionListener<ObjectRootsView.Action> listener = mock(ActionListener.class);
-        frame.addActionListener(listener);
-
-        List<HeapObjectUI> path = new ArrayList<>();
-        path.add(new HeapObjectUI("test", "test"));
-        frame.setPathToRoot(path);
-
-        JTreeFixture tree = frameFixture.tree(ObjectRootsFrame.TREE_NAME);
-        tree.selectRow(0);
-
-        ArgumentCaptor<ActionEvent> argCaptor = ArgumentCaptor.forClass(ActionEvent.class);
-        // We really want to verify that there's exactly one actionPerformend() call.
-        // If there are more events (such as VISIBLE events) fired, this may be a recipe
-        // for desaster if visble events trigger other actions, such as spawning a thread or
-        // starting/stopping a timer.
-        verify(listener).actionPerformed(argCaptor.capture());
-
-        assertEquals(frame, argCaptor.getValue().getSource());
-        
-        assertEquals(Action.OBJECT_SELECTED, argCaptor.getValue().getActionId());
-        assertEquals(path.get(0), argCaptor.getValue().getPayload());
-    }
-
-    @GUITest
-    @Test
-    public void verifySetDetails() {
-        String detailsText = "foo-bar";
-        frame.setObjectDetails(detailsText);
-
-        frame.showView();
-
-        frameFixture.requireVisible();
-
-        JTextComponentFixture textBox = frameFixture.textBox(ObjectRootsFrame.DETAILS_NAME);
-        textBox.requireText(detailsText);
-    }
-
-}
--- a/client/heapdumper/swing/src/test/java/com/redhat/thermostat/client/heap/swing/ServicesAvailableActionTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +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.client.heap.swing;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.client.core.VmInformationService;
-import com.redhat.thermostat.client.heap.HeapDumperService;
-import com.redhat.thermostat.client.heap.swing.Activator;
-import com.redhat.thermostat.client.heap.swing.Activator.ServicesAvailableAction;
-import com.redhat.thermostat.common.ApplicationService;
-import com.redhat.thermostat.common.dao.AgentInfoDAO;
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
-import com.redhat.thermostat.test.StubBundleContext;
-
-public class ServicesAvailableActionTest {
-
-    @Test
-    public void verifyDepsAvailableRegistersVmInformationService() throws Exception {
-        StubBundleContext ctx = new StubBundleContext();
-        Activator activator = new Activator();
-        
-        activator.start(ctx);
-        
-        ServicesAvailableAction action = activator.getServiceAvailableAction();
-        ApplicationService appService = mock(ApplicationService.class);
-        AgentInfoDAO dao = mock(AgentInfoDAO.class);
-        VmMemoryStatDAO vmMemoryDao = mock(VmMemoryStatDAO.class);
-        HeapDAO heapDao = mock(HeapDAO.class);
-        Map<String, Object> services = new HashMap<>();
-        services.put(AgentInfoDAO.class.getName(), dao);
-        services.put(ApplicationService.class.getName(), appService);
-        services.put(VmMemoryStatDAO.class.getName(), vmMemoryDao);
-        services.put(HeapDAO.class.getName(), heapDao);
-        
-        action.dependenciesAvailable(services);
-        
-        assertTrue(ctx.isServiceRegistered(VmInformationService.class.getName(), HeapDumperService.class));
-        
-        // Check no other services are registered
-        assertEquals(1, ctx.getAllServices().size());
-    }
-}
--- a/client/pom.xml	Wed Dec 12 16:42:37 2012 +0100
+++ b/client/pom.xml	Wed Dec 12 15:52:00 2012 -0500
@@ -60,7 +60,6 @@
 
   <modules>
     <module>core</module>
-    <module>heapdumper</module>
     <module>living-vm-filter</module>
     <module>command</module>
     <module>swing</module>
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/DAOFactory.java	Wed Dec 12 16:42:37 2012 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/DAOFactory.java	Wed Dec 12 15:52:00 2012 -0500
@@ -68,8 +68,6 @@
 
     public VmGcStatDAO getVmGcStatDAO();
 
-    public HeapDAO getHeapDAO();
-
     public void registerDAOsAndStorageAsOSGiServices();
     public void unregisterDAOsAndStorageAsOSGiServices();
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/DAOFactoryImpl.java	Wed Dec 12 16:42:37 2012 +0100
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/DAOFactoryImpl.java	Wed Dec 12 15:52:00 2012 -0500
@@ -65,7 +65,6 @@
     private VmClassStatDAO vmClassStatDAO;
     private VmMemoryStatDAO vmMemStatDAO;
     private VmGcStatDAO vmGcStatDAO;
-    private HeapDAO heapDAO;
 
     public DAOFactoryImpl(StorageProvider prov) {
         this(FrameworkUtil.getBundle(DAOFactoryImpl.class).getBundleContext(), prov);
@@ -159,12 +158,6 @@
     }
 
     @Override
-    public HeapDAO getHeapDAO() {
-        ensureStorageConnected();
-        return heapDAO;
-    }
-
-    @Override
     public void registerDAOsAndStorageAsOSGiServices() {
         ensureStorageConnected();
         createDAOs();
@@ -183,7 +176,6 @@
         registerAndRecordService(VmCpuStatDAO.class, getVmCpuStatDAO());
         registerAndRecordService(VmGcStatDAO.class, getVmGcStatDAO());
         registerAndRecordService(VmMemoryStatDAO.class, getVmMemoryStatDAO());
-        registerAndRecordService(HeapDAO.class, getHeapDAO());
     }
 
     /*
@@ -201,7 +193,6 @@
         vmClassStatDAO = new VmClassStatDAOImpl(storage);
         vmMemStatDAO = new VmMemoryStatDAOImpl(storage);
         vmGcStatDAO = new VmGcStatDAOImpl(storage);
-        heapDAO = new HeapDAOImpl(storage);
     }
 
     private <K> void registerAndRecordService(Class<K> serviceType, K serviceImplementation) {
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/HeapDAO.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +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.common.dao;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Collection;
-
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.redhat.thermostat.common.heap.ObjectHistogram;
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.model.HeapInfo;
-
-public interface HeapDAO {
-
-    static final Key<String> heapIdKey = new Key<String>("heapId", false);
-    static final Key<String> heapDumpIdKey = new Key<String>("heapDumpId", false);
-    static final Key<String> histogramIdKey = new Key<String>("histogramId", false);
-
-    public static final Category heapInfoCategory = new Category("vm-heap-info", Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, heapIdKey, heapDumpIdKey, histogramIdKey);
-
-    void putHeapInfo(HeapInfo heapInfo, File heapDumpFile, ObjectHistogram histogramData) throws IOException;
-
-    Collection<HeapInfo> getAllHeapInfo(VmRef vm);
-
-    InputStream getHeapDumpData(HeapInfo heapInfo);
-
-    ObjectHistogram getHistogram(HeapInfo heapInfo);
-
-    HeapInfo getHeapInfo(String heapId);
-
-    HeapDump getHeapDump(HeapInfo heapInfo);
-
-}
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/HeapDAOImpl.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,162 +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.common.dao;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.redhat.thermostat.common.heap.ObjectHistogram;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.Query;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.Query.Criteria;
-import com.redhat.thermostat.storage.model.HeapInfo;
-
-class HeapDAOImpl implements HeapDAO {
-
-    private static final Logger log = LoggingUtils.getLogger(HeapDAOImpl.class);
-
-    private final Storage storage;
-
-    HeapDAOImpl(Storage storage) {
-        this.storage = storage;
-        storage.registerCategory(heapInfoCategory);
-    }
-
-    @Override
-    public void putHeapInfo(HeapInfo heapInfo, File heapDumpData, ObjectHistogram histogramData) throws IOException {
-        heapInfo.setAgentId(storage.getAgentId());
-        String heapId = heapInfo.getAgentId() + "-" + heapInfo.getVmId() + "-" + heapInfo.getTimeStamp();
-        System.err.println("assigning heapId: " + heapId);
-        heapInfo.setHeapId(heapId);
-        String heapDumpId = "heapdump-" + heapId;
-        String histogramId = "histogram-" + heapId;
-        if (heapDumpData != null) {
-            heapInfo.setHeapDumpId(heapDumpId);
-        }
-        if (histogramData != null) {
-            heapInfo.setHistogramId(histogramId);
-        }
-        storage.putPojo(heapInfoCategory, false, heapInfo);
-        if (heapDumpData != null) {
-            storage.saveFile(heapDumpId, new FileInputStream(heapDumpData));
-        }
-        if (histogramData != null) {
-            ByteArrayOutputStream baos = new ByteArrayOutputStream();
-            try {
-                ObjectOutputStream oos = new ObjectOutputStream(baos);
-                oos.writeObject(histogramData);
-                ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-                storage.saveFile(histogramId, bais);
-            } catch (IOException e) {
-                e.printStackTrace();
-                log.log(Level.SEVERE, "Unexpected error while writing histogram", e);
-            }
-        }
-    }
-
-    @Override
-    public Collection<HeapInfo> getAllHeapInfo(VmRef vm) {
-        Query query = storage.createQuery()
-                .from(heapInfoCategory)
-                .where(Key.AGENT_ID, Criteria.EQUALS, vm.getAgent().getAgentId())
-                .where(Key.VM_ID, Criteria.EQUALS, vm.getId());
-        Cursor<HeapInfo> cursor = storage.findAllPojos(query, HeapInfo.class);
-        Collection<HeapInfo> heapInfos = new ArrayList<>();
-        while (cursor.hasNext()) {
-            heapInfos.add(cursor.next());
-        }
-        return heapInfos;
-    }
-
-    @Override
-    public InputStream getHeapDumpData(HeapInfo heapInfo) {
-        return storage.loadFile(heapInfo.getHeapDumpId());
-    }
-
-    @Override
-    public ObjectHistogram getHistogram(HeapInfo heapInfo) {
-        
-        try (InputStream in = storage.loadFile(heapInfo.getHistogramId())) {
-            ObjectInputStream ois = new ObjectInputStream(in);
-            return (ObjectHistogram) ois.readObject();
-        } catch (IOException | ClassNotFoundException e) {
-            log.log(Level.SEVERE, "Unexpected error while reading histogram", e);
-            return null;
-        }
-    }
-
-    @Override
-    public HeapInfo getHeapInfo(String heapId) {
-        Query query = storage.createQuery()
-                .from(heapInfoCategory)
-                .where(heapIdKey, Criteria.EQUALS, heapId);
-        HeapInfo found = null;
-        try {
-            found = storage.findPojo(query, HeapInfo.class);
-        } catch (IllegalArgumentException iae) {
-            /*
-             * if the heap id is not found, we get a nice
-             * IllegalArgumentException but check if the illegal argument
-             * exception is caused by that before propagating it.
-             */
-            if (!iae.getMessage().contains("invalid ObjectId")) {
-                throw iae;
-            }
-        }
-        return found;
-    }
-
-    @Override
-    public HeapDump getHeapDump(HeapInfo heapInfo) {
-        return new HeapDump(heapInfo, this);
-    }
-
-}
--- a/common/core/src/main/java/com/redhat/thermostat/common/heap/HeapDump.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,232 +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.common.heap;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.FileAlreadyExistsException;
-import java.nio.file.Files;
-import java.nio.file.attribute.PosixFilePermissions;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import org.apache.lucene.analysis.SimpleAnalyzer;
-import org.apache.lucene.document.Document;
-import org.apache.lucene.document.Field;
-import org.apache.lucene.index.CorruptIndexException;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.IndexWriter;
-import org.apache.lucene.index.IndexWriterConfig;
-import org.apache.lucene.index.Term;
-import org.apache.lucene.search.IndexSearcher;
-import org.apache.lucene.search.ScoreDoc;
-import org.apache.lucene.search.TopDocs;
-import org.apache.lucene.search.WildcardQuery;
-import org.apache.lucene.store.Directory;
-import org.apache.lucene.store.LockObtainFailedException;
-import org.apache.lucene.store.RAMDirectory;
-import org.apache.lucene.util.Version;
-
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.storage.model.HeapInfo;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-import com.sun.tools.hat.internal.model.Snapshot;
-import com.sun.tools.hat.internal.parser.Reader;
-
-/**
- * NOTE: This class is thread-safe with respect to loading the heapdump and creating the index.
- */
-public class HeapDump {
-
-    private static final String INDEX_FIELD_OBJECT_ID = "objectId";
-
-    private static final String INDEX_FIELD_CLASSNAME = "classname";
-
-    private static final Logger log = LoggingUtils.getLogger(HeapDump.class);
-
-    private final HeapInfo heapInfo;
-
-    private final HeapDAO heapDAO;
-
-    private Snapshot snapshot;
-
-    private Directory luceneIndex;
-
-    public HeapDump(HeapInfo heapInfo, HeapDAO heapDAO) {
-        this.heapInfo = heapInfo;
-        this.heapDAO = heapDAO;
-    }
-
-    public long getTimestamp() {
-        return heapInfo.getTimeStamp();
-    }
-
-    @Override
-    public String toString() {
-        return "[" + new Date(getTimestamp()) +"] ";
-    }
-
-    public ObjectHistogram getHistogram() throws IOException {
-        return heapDAO.getHistogram(heapInfo);
-    }
-
-    public HeapInfo getInfo() {
-        return heapInfo;
-    }
-
-    private synchronized Directory getLuceneIndex() {
-        if (luceneIndex == null) {
-            try {
-                luceneIndex = createLuceneIndex();
-            } catch (IOException ex) {
-                log.log(Level.SEVERE, "Unexpected IO Exception while creating heap dump index", ex);
-                return null;
-            }
-        }
-        return luceneIndex;
-    }
-
-    private Directory createLuceneIndex() throws IOException,
-            CorruptIndexException, LockObtainFailedException {
-
-        loadHeapDumpIfNecessary();
-
-        Enumeration<JavaHeapObject> thingos = snapshot.getThings();
-        Directory dir = new RAMDirectory();
-        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_36, new SimpleAnalyzer(Version.LUCENE_36));
-        IndexWriter writer = new IndexWriter(dir, indexWriterConfig);
-        while (thingos.hasMoreElements()) {
-            JavaHeapObject thingo = thingos.nextElement();
-            Document doc = new Document();
-            doc.add(new Field(INDEX_FIELD_CLASSNAME, thingo.getClazz().getName(), Field.Store.YES, Field.Index.NOT_ANALYZED));
-            doc.add(new Field(INDEX_FIELD_OBJECT_ID, thingo.getIdString(), Field.Store.YES, Field.Index.NOT_ANALYZED));
-            writer.addDocument(doc);
-        }
-        writer.close();
-        return dir;
-    }
-
-    public Snapshot getSnapshot() {
-        loadHeapDumpIfNecessary();
-        return snapshot;
-    }
-
-    private synchronized void loadHeapDumpIfNecessary() {
-        if (snapshot == null) {
-            try {
-                loadHeapDump();
-            } catch (IOException e) {
-                log.log(Level.SEVERE, "Unexpected IO Exception while loading heap dump", e);
-            }
-        }
-    }
-
-    private void loadHeapDump() throws IOException {
-        String filename = "heapdump-" + heapInfo.getHeapId();
-        File tmpDir = getOrCreateHeapDumpDir();
-        File tmpFile = new File(tmpDir, filename);
-        if (! tmpFile.exists()) {
-            try (InputStream in = heapDAO.getHeapDumpData(heapInfo);) {
-                Files.copy(in, tmpFile.toPath());
-            }
-            
-        }
-        snapshot = Reader.readFile(tmpFile.getAbsolutePath(), true, 0);
-        snapshot.resolve(true);
-    }
-
-    private File getOrCreateHeapDumpDir() throws IOException {
-        String dirname = "thermostat-" + System.getProperty("user.name");
-        File tmpFile = new File(System.getProperty("java.io.tmpdir"), dirname);
-        if (! tmpFile.exists()) {
-            Files.createDirectory(tmpFile.toPath(), PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rwx------")));
-            return tmpFile;
-        } else {
-            if (tmpFile.isDirectory()) {
-                return tmpFile;
-            } else {
-                throw new FileAlreadyExistsException(tmpFile.getAbsolutePath());
-            }
-        }
-    }
-
-    /**
-     * Find objects with class names matching the given pattern
-     * @param wildCardClassNamePattern a case-sensitive wildcard pattern to match class names against
-     * @param limit the maximum number of results to return
-     * @return a collection of object ids that can be used with {@link #findObject(String)}
-     */
-    public Collection<String> searchObjects(String wildCardClassNamePattern, int limit) {
-        Directory searchIndex = getLuceneIndex();
-
-        WildcardQuery query = new WildcardQuery(new Term(INDEX_FIELD_CLASSNAME, wildCardClassNamePattern));
-        Collection<String> results = new ArrayList<String>();
-        try {
-            IndexReader indexReader = IndexReader.open(searchIndex);
-            IndexSearcher searcher = new IndexSearcher(indexReader);
-            TopDocs found = searcher.search(query, limit);
-            for (ScoreDoc scoreDoc : found.scoreDocs) {
-                Document doc = searcher.doc(scoreDoc.doc);
-                String objectId = doc.get(INDEX_FIELD_OBJECT_ID);
-                results.add(objectId);
-            }
-            searcher.close();
-        } catch (IOException e) {
-            log.log(Level.SEVERE, "Unexpected IO Exception while searching heap dump index", e);
-        }
-        return results;
-    }
-
-    public JavaHeapObject findObject(String id) {
-        loadHeapDumpIfNecessary();
-        return snapshot.findThing(id);
-    }
-
-    public boolean equals(Object o) {
-        return o instanceof HeapDump && ((HeapDump) o).heapInfo.equals(heapInfo);
-    }
-
-    public int hashCode() {
-        return heapInfo.hashCode();
-    }
-}
--- a/common/core/src/main/java/com/redhat/thermostat/common/heap/HistogramLoader.java	Wed Dec 12 16:42:37 2012 +0100
+++ /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.common.heap;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Enumeration;
-
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-import com.sun.tools.hat.internal.model.Snapshot;
-import com.sun.tools.hat.internal.parser.Reader;
-
-public class HistogramLoader {
-
-    public ObjectHistogram load(String filename) throws IOException {
-        Snapshot snapshot = loadHeapdump(filename);
-        return computeHistogram(snapshot);
-    }
-
-    private Snapshot loadHeapdump(String filename) throws IOException {
-        File heapdump = new File(filename);
-        Snapshot snapshot = Reader.readFile(heapdump.getAbsolutePath(), true, 0);
-        snapshot.resolve(true);
-        return snapshot;
-    }
-
-    private ObjectHistogram computeHistogram(Snapshot snapshot) {
-        Enumeration<JavaHeapObject> thingos = snapshot.getThings();
-        ObjectHistogram histogram = new ObjectHistogram();
-        while (thingos.hasMoreElements()) {
-            JavaHeapObject thingo = thingos.nextElement();
-            histogram.addThing(thingo);
-        }
-        return histogram;
-    }
-
-}
--- a/common/core/src/main/java/com/redhat/thermostat/common/heap/HistogramRecord.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +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.common.heap;
-
-import java.io.Serializable;
-import java.util.Objects;
-
-public class HistogramRecord implements Serializable {
-
-    String classname;
-    long numberOf;
-    long totalSize;
-
-    HistogramRecord(String classname) {
-        this(classname, 0, 0);
-    }
-
-    public HistogramRecord(String classname, long numberOf, long totalSize) {
-        this.classname = classname;
-        this.numberOf = numberOf;
-        this.totalSize = totalSize;
-    }
-
-    public String getClassname() {
-        return classname;
-    }
-
-    public long getNumberOf() {
-        return numberOf;
-    }
-
-    public long getTotalSize() {
-        return totalSize;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (! (o instanceof HistogramRecord)) {
-            return false;
-        }
-        HistogramRecord other = (HistogramRecord) o;
-        return Objects.equals(classname, other.classname) && numberOf == other.numberOf && totalSize == other.totalSize;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(classname, numberOf, totalSize);
-    }
-}
\ No newline at end of file
--- a/common/core/src/main/java/com/redhat/thermostat/common/heap/ObjectHistogram.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +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.common.heap;
-
-import java.io.PrintStream;
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-import com.sun.tools.hat.internal.model.JavaClass;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-
-public class ObjectHistogram implements Serializable {
-
-    private Map<String, HistogramRecord> histogram = new HashMap<>();
-
-    public void addThing(JavaHeapObject thing) {
-        JavaClass clazz = thing.getClazz();
-        HistogramRecord record = histogram.get(clazz.getName());
-        if (record == null) {
-            record = new HistogramRecord(clazz.getName());
-            histogram.put(clazz.getName(), record);
-        }
-        record.numberOf++;
-        record.totalSize += thing.getSize();
-    }
-
-    public Collection<HistogramRecord> getHistogram() {
-        return histogram.values();
-    }
-
-    public void print(PrintStream out) {
-        for (Map.Entry<String, HistogramRecord> entry : histogram.entrySet()) {
-            HistogramRecord record = entry.getValue();
-            out.println(record.classname + ", " + record.numberOf + ", " + record.totalSize);
-        }
-    }
-}
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/HeapDAOTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,283 +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.common.dao;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.same;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.ObjectOutputStream;
-import java.util.Collection;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import com.redhat.thermostat.common.heap.HistogramRecord;
-import com.redhat.thermostat.common.heap.ObjectHistogram;
-import com.redhat.thermostat.storage.core.Category;
-import com.redhat.thermostat.storage.core.Cursor;
-import com.redhat.thermostat.storage.core.Key;
-import com.redhat.thermostat.storage.core.Query;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.Query.Criteria;
-import com.redhat.thermostat.storage.model.HeapInfo;
-import com.redhat.thermostat.test.MockQuery;
-import com.sun.tools.hat.internal.model.JavaClass;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-
-
-public class HeapDAOTest {
-
-    private HeapDAO dao;
-    private Storage storage;
-    private HeapInfo heapInfo;
-    private File heapDumpData;
-    private ObjectHistogram histogram;
-    private InputStream histogramData;
-
-    @Before
-    public void setUp() throws IOException {
-        storage = mock(Storage.class);
-        when(storage.getAgentId()).thenReturn("test");
-        when(storage.createQuery()).then(new Answer<Query>() {
-            @Override
-            public Query answer(InvocationOnMock invocation) throws Throwable {
-                return new MockQuery();
-            }
-        });
-
-        dao = new HeapDAOImpl(storage);
-        
-        heapInfo = new HeapInfo(123, 12345);
-        byte[] data = new byte[] { 1, 2, 3 };
-        heapDumpData = File.createTempFile("test", "test");
-        FileOutputStream out = new FileOutputStream(heapDumpData);
-        out.write(data);
-        out.close();
-        histogramData = createHistogramData();
-
-        // Setup for reading data from DB.
-        MockQuery findAllQuery = new MockQuery()
-            .from(HeapDAO.heapInfoCategory)
-            .where(Key.AGENT_ID, Criteria.EQUALS, "123")
-            .where(Key.VM_ID, Criteria.EQUALS, 234);
-
-        @SuppressWarnings("unchecked")
-        Cursor<HeapInfo> cursor = mock(Cursor.class);
-        HeapInfo info1 = new HeapInfo(234, 12345L);
-        info1.setAgentId("123");
-        info1.setHeapDumpId("test1");
-        info1.setHistogramId("histotest1");
-
-        HeapInfo info2 = new HeapInfo(234, 23456L);
-        info2.setAgentId("123");
-        info2.setHeapDumpId("test2");
-        info2.setHistogramId("histotest2");
-
-        when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(info1).thenReturn(info2).thenReturn(null);
-        when(storage.findAllPojos(findAllQuery, HeapInfo.class)).thenReturn(cursor);
-
-        // Setup for reading heapdump data.
-        when(storage.loadFile("test-heap")).thenReturn(new ByteArrayInputStream(data));
-        when(storage.loadFile("test-histo")).thenReturn(histogramData);
-
-        // We dont check for AGENT_ID. That's enforced/added/checked by Storage
-
-    }
-
-    private InputStream createHistogramData() throws IOException {
-        histogram = new ObjectHistogram();
-
-        JavaClass cls1 = mock(JavaClass.class);
-        JavaHeapObject obj1 = mock(JavaHeapObject.class);
-        when(cls1.getName()).thenReturn("class1");
-        when(obj1.getClazz()).thenReturn(cls1);
-        when(obj1.getSize()).thenReturn(5);
-        JavaHeapObject obj2 = mock(JavaHeapObject.class);
-        when(obj2.getClazz()).thenReturn(cls1);
-        when(obj2.getSize()).thenReturn(3);
-        JavaClass cls2 = mock(JavaClass.class);
-        JavaHeapObject obj3 = mock(JavaHeapObject.class);
-        when(cls2.getName()).thenReturn("class2");
-        when(obj3.getClazz()).thenReturn(cls2);
-        when(obj3.getSize()).thenReturn(10);
-
-        histogram.addThing(obj1);
-        histogram.addThing(obj2);
-        histogram.addThing(obj3);
-
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        ObjectOutputStream oos = new ObjectOutputStream(baos);
-        oos.writeObject(histogram);
-        return new ByteArrayInputStream(baos.toByteArray());
-    }
-
-    @After
-    public void tearDown() {
-        histogramData = null;
-        histogram = null;
-        heapDumpData.delete();
-        heapDumpData = null;
-        heapInfo = null;
-        dao = null;
-        storage = null;
-    }
-
-    @Test
-    public void testCategory() {
-        Category category = HeapDAO.heapInfoCategory;
-        assertNotNull(category);
-        assertEquals("vm-heap-info", category.getName());
-        Collection<Key<?>> keys = category.getKeys();
-        assertEquals(6, keys.size());
-        assertTrue(keys.contains(new Key<>("agentId", true)));
-        assertTrue(keys.contains(new Key<>("vmId", true)));
-        assertTrue(keys.contains(new Key<>("timeStamp", false)));
-        assertTrue(keys.contains(new Key<>("heapId", false)));
-        assertTrue(keys.contains(new Key<>("heapDumpId", false)));
-        assertTrue(keys.contains(new Key<>("histogramId", false)));
-    }
-
-    @Test
-    public void testPutHeapInfo() throws IOException {
-        dao.putHeapInfo(heapInfo, heapDumpData, histogram);
-
-        verify(storage).putPojo(HeapDAO.heapInfoCategory, false, heapInfo);
-
-        ArgumentCaptor<InputStream> data = ArgumentCaptor.forClass(InputStream.class);
-        verify(storage).saveFile(eq("heapdump-test-123-12345"), data.capture());
-        InputStream in = data.getValue();
-        assertEquals(1, in.read());
-        assertEquals(2, in.read());
-        assertEquals(3, in.read());
-        assertEquals(-1, in.read());
-        assertEquals("test-123-12345", heapInfo.getHeapId());
-        ArgumentCaptor<InputStream> histoStream = ArgumentCaptor.forClass(InputStream.class);
-        verify(storage).saveFile(eq("histogram-test-123-12345"), histoStream.capture());
-        InputStream histoActual = histoStream.getValue();
-        int expected;
-        int actual;
-        do {
-            expected = histogramData.read();
-            actual = histoActual.read();
-            assertEquals(expected, actual);
-        } while (expected != -1 && actual != -1);
-    }
-
-    @Test
-    public void testPutHeapInfoWithoutDump() throws IOException {
-        dao.putHeapInfo(heapInfo, null, null);
-
-        verify(storage).putPojo(HeapDAO.heapInfoCategory, false, heapInfo);
-
-        verify(storage, never()).saveFile(anyString(), any(InputStream.class));
-        assertEquals("test-123-12345", heapInfo.getHeapId());
-    }
-
-    @Test
-    public void testGetAllHeapInfo() {
-        
-        // verify a connection key has been created before requesting the
-        // heap dumps
-        verify(storage).registerCategory(HeapDAO.heapInfoCategory);
-        
-        HostRef host = new HostRef("123", "test-host");
-        VmRef vm = new VmRef(host, 234, "test-vm");
-        Collection<HeapInfo> heapInfos = dao.getAllHeapInfo(vm);
-        
-        HeapInfo info1 = new HeapInfo(234, 12345);
-        info1.setHeapDumpId("test1");
-        info1.setHistogramId("histotest1");
-        
-        HeapInfo info2 = new HeapInfo(234, 23456);
-        info2.setHeapDumpId("test2");
-        info2.setHistogramId("histotest2");
-        
-        assertEquals(2, heapInfos.size());
-        assertTrue(heapInfos.contains(info1));
-        assertTrue(heapInfos.contains(info2));
-    }
-
-    @Test
-    public void testGetHeapDump() throws IOException {
-        heapInfo.setHeapDumpId("test-heap");
-        InputStream in = dao.getHeapDumpData(heapInfo);
-        assertEquals(1, in.read());
-        assertEquals(2, in.read());
-        assertEquals(3, in.read());
-        assertEquals(-1, in.read());
-    }
-
-    @Test
-    public void testGetHistogram() throws IOException {
-        heapInfo.setHistogramId("test-histo");
-        ObjectHistogram histo = dao.getHistogram(heapInfo);
-        Collection<HistogramRecord> histoRecs = histo.getHistogram();
-        assertEquals(2, histoRecs.size());
-        assertTrue(histoRecs.contains(new HistogramRecord("class1", 2, 8)));
-        assertTrue(histoRecs.contains(new HistogramRecord("class2", 1, 10)));
-    }
-
-    @Test
-    public void testInvalidHeapId() throws IOException {
-        storage = mock(Storage.class);
-        when(storage.createQuery()).thenReturn(new MockQuery());
-        when(storage.findPojo(any(Query.class), same(HeapInfo.class))).thenThrow(new IllegalArgumentException("invalid ObjectId"));
-        dao = new HeapDAOImpl(storage);
-        heapInfo = dao.getHeapInfo("some-random-heap-id");
-        assertTrue(heapInfo == null);
-    }
-}
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/MongoDAOFactoryTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/MongoDAOFactoryTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -138,19 +138,13 @@
     }
 
     @Test
-    public void testGetHeapDAO() {
-        HeapDAO dao = daoFactory.getHeapDAO();
-        assertNotNull(dao);
-    }
-
-    @Test
     public void testServiceRegistration() {
         assertEquals(0, bundleContext.getAllServices().size());
 
         daoFactory.registerDAOsAndStorageAsOSGiServices();
 
         // currently 12 DAOs and Storage are registered
-        assertEquals(13, bundleContext.getAllServices().size());
+        assertEquals(12, bundleContext.getAllServices().size());
     }
 
     @Test
--- a/common/core/src/test/java/com/redhat/thermostat/common/heap/HeapDumpTest.java	Wed Dec 12 16:42:37 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,140 +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.common.heap;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Collection;
-import java.util.zip.GZIPInputStream;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.common.dao.HeapDAO;
-import com.redhat.thermostat.storage.model.HeapInfo;
-import com.sun.tools.hat.internal.model.JavaHeapObject;
-
-/*
- * This testcase uses a minimalistic heapdump that is stored as binary in
- * src/test/resources.
- *
- * It is generated from a simple Java class:
- * public class Test {
- *   public static void main(String[] args) throws Exception {
- *     Thread.sleep(1000000);
- *   }
- * }
- *
- * The actual heapdump can be generated like this:
- *
- * jmap -dump:format=b,file=heapdump.hprof $PID
- * 
- * where $PID is the PID of the Java process running the above simple program.
- *
- * Finally, the heapdump is gzipped:
- *
- * gzip heapdump.hprof
- *
- */
-public class HeapDumpTest {
-
-    private static final String HEAP_ID = "TEST_HEAP_ID";
-
-    private HeapDump heapDump;
-
-    @Before
-    public void setUp() throws IOException {
-        InputStream in = getClass().getResourceAsStream("/heapdump.hprof.gz");
-        GZIPInputStream gzipIn = new GZIPInputStream(in);
-
-        HeapInfo heapInfo = mock(HeapInfo.class);
-        when(heapInfo.getHeapId()).thenReturn(HEAP_ID);
-        HeapDAO heapDAO = mock(HeapDAO.class);
-        when(heapDAO.getHeapDumpData(heapInfo)).thenReturn(gzipIn);
-        heapDump = new HeapDump(heapInfo, heapDAO);
-    }
-
-    @Test
-    public void testSearchObjects() {
-        Collection<String> foundObjectIds = heapDump.searchObjects("java.util.ArrayDeque", 10);
-        assertEquals(8, foundObjectIds.size());
-        assertTrue(foundObjectIds.contains("0x7d704eb20"));
-        assertTrue(foundObjectIds.contains("0x7d70485e8"));
-        assertTrue(foundObjectIds.contains("0x7d704aed8"));
-        assertTrue(foundObjectIds.contains("0x7d70447a0"));
-        assertTrue(foundObjectIds.contains("0x7d704d438"));
-        assertTrue(foundObjectIds.contains("0x7d70471e8"));
-        assertTrue(foundObjectIds.contains("0x7d7049aa0"));
-        assertTrue(foundObjectIds.contains("0x7d704bfe0"));
-    }
-
-    @Test
-    public void testSearchObjectsWithLimit() {
-        Collection<String> foundObjectIds = heapDump.searchObjects("java.util.ArrayDeque", 2);
-        assertEquals(2, foundObjectIds.size());
-        // we know 2 things matched. Don't know which ones (there is no guarentee on order).
-        String[] possibleMatches = new String[] {
-            "0x7d704eb20",
-            "0x7d70485e8",
-            "0x7d704aed8",
-            "0x7d70447a0",
-            "0x7d704d438",
-            "0x7d70471e8",
-            "0x7d7049aa0",
-            "0x7d704bfe0",
-        };
-        int totalMatches = 0;
-        for (String possible : possibleMatches) {
-            if (foundObjectIds.contains(possible)) {
-                totalMatches++;
-            }
-        }
-        assertEquals(2, totalMatches);
-    }
-
-    @Test
-    public void testFindObject() {
-        JavaHeapObject obj = heapDump.findObject("0x7d704eb20");
-        assertEquals("0x7d704eb20", obj.getIdString());
-        assertEquals("java.util.ArrayDeque", obj.getClazz().getName());
-    }
-}
Binary file common/core/src/test/resources/heapdump.hprof.gz has changed
--- a/distribution/config/commands/agent.properties	Wed Dec 12 16:42:37 2012 +0100
+++ b/distribution/config/commands/agent.properties	Wed Dec 12 15:52:00 2012 -0500
@@ -9,7 +9,8 @@
           thermostat-agent-cli-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
           thermostat-agent-command-@project.version@.jar, \
-          thermostat-agent-heapdumper-@project.version@.jar, \
+          thermostat-vm-heap-analysis-common-@project.version@.jar, \
+          thermostat-vm-heap-analysis-agent-@project.version@.jar, \
           thermostat-killvm-agent-@project.version@.jar, \
           thermostat-thread-collector-@project.version@.jar, \
           thermostat-thread-harvester-@project.version@.jar, \
--- a/distribution/config/commands/dump-heap.properties	Wed Dec 12 16:42:37 2012 +0100
+++ b/distribution/config/commands/dump-heap.properties	Wed Dec 12 15:52:00 2012 -0500
@@ -2,7 +2,8 @@
           thermostat-client-core-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
           thermostat-client-command-@project.version@.jar, \
-          thermostat-client-heapdumper-core-@project.version@.jar, \
+          thermostat-vm-heap-analysis-common-@project.version@.jar, \
+          thermostat-vm-heap-analysis-command-@project.version@.jar, \
           thermostat-storage-mongodb-${project.version}.jar, \
           mongo.jar, \
           commons-beanutils.jar, \
--- a/distribution/config/commands/find-objects.properties	Wed Dec 12 16:42:37 2012 +0100
+++ b/distribution/config/commands/find-objects.properties	Wed Dec 12 15:52:00 2012 -0500
@@ -1,7 +1,8 @@
 bundles = thermostat-client-core-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
           thermostat-client-command-@project.version@.jar, \
-          thermostat-client-heapdumper-core-@project.version@.jar, \
+          thermostat-vm-heap-analysis-common-@project.version@.jar, \
+          thermostat-vm-heap-analysis-command-@project.version@.jar, \
           thermostat-storage-mongodb-${project.version}.jar, \
           mongo.jar, \
           commons-beanutils.jar, \
--- a/distribution/config/commands/find-root.properties	Wed Dec 12 16:42:37 2012 +0100
+++ b/distribution/config/commands/find-root.properties	Wed Dec 12 15:52:00 2012 -0500
@@ -1,7 +1,8 @@
 bundles = thermostat-client-core-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
           thermostat-client-command-@project.version@.jar, \
-          thermostat-client-heapdumper-core-@project.version@.jar, \
+          thermostat-vm-heap-analysis-common-@project.version@.jar, \
+          thermostat-vm-heap-analysis-command-@project.version@.jar, \
           thermostat-storage-mongodb-${project.version}.jar, \
           mongo.jar, \
           commons-beanutils.jar, \
--- a/distribution/config/commands/gui.properties	Wed Dec 12 16:42:37 2012 +0100
+++ b/distribution/config/commands/gui.properties	Wed Dec 12 15:52:00 2012 -0500
@@ -26,8 +26,10 @@
           thermostat-vm-gc-client-swing-@project.version@.jar, \
           thermostat-vm-memory-client-core-@project.version@.jar, \
           thermostat-vm-memory-client-swing-@project.version@.jar, \
-          thermostat-client-heapdumper-core-@project.version@.jar, \
-          thermostat-client-heapdumper-swing-@project.version@.jar, \
+          thermostat-vm-heap-analysis-client-core-@project.version@.jar, \
+          thermostat-vm-heap-analysis-client-swing-@project.version@.jar, \
+          thermostat-vm-heap-analysis-common-@project.version@.jar, \
+          thermostat-vm-heap-analysis-command-@project.version@.jar, \
           thermostat-killvm-client-swing-@project.version@.jar, \
           thermostat-vm-classstat-client-core-@project.version@.jar, \
           thermostat-vm-classstat-client-swing-@project.version@.jar, \
--- a/distribution/config/commands/list-heap-dumps.properties	Wed Dec 12 16:42:37 2012 +0100
+++ b/distribution/config/commands/list-heap-dumps.properties	Wed Dec 12 15:52:00 2012 -0500
@@ -6,7 +6,8 @@
           thermostat-client-core-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
           thermostat-client-command-@project.version@.jar, \
-          thermostat-client-heapdumper-core-@project.version@.jar, \
+          thermostat-vm-heap-analysis-common-@project.version@.jar, \
+          thermostat-vm-heap-analysis-command-@project.version@.jar, \
           thermostat-web-common-${project.version}.jar, \
           thermostat-web-client-${project.version}.jar, \
           httpcomponents-core.jar, \
--- a/distribution/config/commands/object-info.properties	Wed Dec 12 16:42:37 2012 +0100
+++ b/distribution/config/commands/object-info.properties	Wed Dec 12 15:52:00 2012 -0500
@@ -6,7 +6,8 @@
           thermostat-client-core-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
           thermostat-client-command-@project.version@.jar, \
-          thermostat-client-heapdumper-core-@project.version@.jar, \
+          thermostat-vm-heap-analysis-common-@project.version@.jar, \
+          thermostat-vm-heap-analysis-command-@project.version@.jar, \
           thermostat-web-common-${project.version}.jar, \
           thermostat-web-client-${project.version}.jar, \
           httpcomponents-core.jar, \
--- a/distribution/config/commands/save-heap-dump-to-file.properties	Wed Dec 12 16:42:37 2012 +0100
+++ b/distribution/config/commands/save-heap-dump-to-file.properties	Wed Dec 12 15:52:00 2012 -0500
@@ -6,7 +6,8 @@
           thermostat-client-core-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
           thermostat-client-command-@project.version@.jar, \
-          thermostat-client-heapdumper-core-@project.version@.jar, \
+          thermostat-vm-heap-analysis-common-@project.version@.jar, \
+          thermostat-vm-heap-analysis-command-@project.version@.jar, \
           thermostat-web-common-${project.version}.jar, \
           thermostat-web-client-${project.version}.jar, \
           httpcomponents-core.jar, \
--- a/distribution/config/commands/show-heap-histogram.properties	Wed Dec 12 16:42:37 2012 +0100
+++ b/distribution/config/commands/show-heap-histogram.properties	Wed Dec 12 15:52:00 2012 -0500
@@ -6,7 +6,8 @@
           thermostat-client-core-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
           thermostat-client-command-@project.version@.jar, \
-          thermostat-client-heapdumper-core-@project.version@.jar, \
+          thermostat-vm-heap-analysis-common-@project.version@.jar, \
+          thermostat-vm-heap-analysis-command-@project.version@.jar, \
           thermostat-web-common-${project.version}.jar, \
           thermostat-web-client-${project.version}.jar, \
           httpcomponents-core.jar, \
--- a/distribution/pom.xml	Wed Dec 12 16:42:37 2012 +0100
+++ b/distribution/pom.xml	Wed Dec 12 15:52:00 2012 -0500
@@ -421,6 +421,11 @@
       <version>${project.version}</version>
     </dependency>
     <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-vm-heap-analysis-client-swing</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
         <groupId>com.redhat.thermostat</groupId>
         <artifactId>thermostat-osgi-living-vm-filter-swing</artifactId>
         <version>${project.version}</version>
@@ -442,7 +447,7 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-agent-heapdumper</artifactId>
+      <artifactId>thermostat-vm-heap-analysis-agent</artifactId>
       <version>${project.version}</version>
     </dependency>
     <dependency>
@@ -472,11 +477,6 @@
     </dependency>
     <dependency>
         <groupId>com.redhat.thermostat</groupId>
-        <artifactId>thermostat-client-heapdumper-swing</artifactId>
-        <version>${project.version}</version>
-    </dependency>
-    <dependency>
-        <groupId>com.redhat.thermostat</groupId>
         <artifactId>thermostat-keyring</artifactId>
         <version>${project.version}</version>
     </dependency>
--- a/eclipse/com.redhat.thermostat.eclipse.chart.common/META-INF/MANIFEST.MF	Wed Dec 12 16:42:37 2012 +0100
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/META-INF/MANIFEST.MF	Wed Dec 12 15:52:00 2012 -0500
@@ -13,7 +13,6 @@
  com.redhat.thermostat.client.ui,
  com.redhat.thermostat.common,
  com.redhat.thermostat.common.dao,
- com.redhat.thermostat.common.heap,
  com.redhat.thermostat.common.locale,
  com.redhat.thermostat.common.utils,
  com.redhat.thermostat.eclipse,
--- a/pom.xml	Wed Dec 12 16:42:37 2012 +0100
+++ b/pom.xml	Wed Dec 12 15:52:00 2012 -0500
@@ -140,6 +140,7 @@
     <module>vm-gc</module>
     <module>vm-classstat</module>
     <module>vm-memory</module>
+    <module>vm-heap-analysis</module>
     <!-- development related modules -->
     <module>dev</module>
   </modules>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/agent/pom.xml	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,125 @@
+<?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-vm-heap-analysis</artifactId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>thermostat-vm-heap-analysis-agent</artifactId>
+  <packaging>bundle</packaging>
+
+  <name>Thermostat VM Heap Analysis Agent plugin</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>org.powermock</groupId>
+      <artifactId>powermock-api-mockito</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-agent-command</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-vm-heap-analysis-common</artifactId>
+      <version>${project.version}</version>
+    </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.vm.heap.analysis.agent.internal.Activator</Bundle-Activator>
+            <Bundle-SymbolicName>com.redhat.thermostat.vm.heap.analysis.agent</Bundle-SymbolicName>
+            <Export-Package>
+              com.redhat.thermostat.vm.heap.analysis.agent
+            </Export-Package>
+            <Private-Package>
+              com.redhat.thermostat.vm.heap.analysis.agent.internal
+            </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/vm-heap-analysis/agent/src/main/java/com/redhat/thermostat/vm/heap/analysis/agent/internal/Activator.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,85 @@
+/*
+ * 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.vm.heap.analysis.agent.internal;
+
+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.vm.heap.analysis.common.HeapDAO;
+
+public class Activator implements BundleActivator {
+
+    private ReceiverRegistry receivers;
+
+    private HeapDumpReceiver receiver = null;
+
+    private ServiceTracker heapDumpCommandReceiverTracker;
+
+    @Override
+    public void start(BundleContext context) {
+        receivers = new ReceiverRegistry(context);
+
+        heapDumpCommandReceiverTracker = new ServiceTracker(context, HeapDAO.class.getName(), null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                HeapDAO service = (HeapDAO) super.addingService(reference);
+                receiver = new HeapDumpReceiver(service);
+                receivers.registerReceiver(receiver);
+                return service;
+            }
+
+            @Override
+            public void removedService(ServiceReference reference, Object service) {
+                receivers.unregisterReceivers();
+                super.removedService(reference, service);
+            }
+        };
+        heapDumpCommandReceiverTracker.open();
+
+    }
+
+    @Override
+    public void stop(BundleContext context) {
+        heapDumpCommandReceiverTracker.close();
+
+        receivers.unregisterReceivers();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/agent/src/main/java/com/redhat/thermostat/vm/heap/analysis/agent/internal/HeapDumpException.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,59 @@
+/*
+ * 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.vm.heap.analysis.agent.internal;
+
+@SuppressWarnings("serial")
+public class HeapDumpException extends Exception {
+
+    public HeapDumpException() {
+        super();
+    }
+
+    public HeapDumpException(String message) {
+        super(message);
+    }
+
+    public HeapDumpException(Throwable cause) {
+        super(cause);
+    }
+
+    public HeapDumpException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/agent/src/main/java/com/redhat/thermostat/vm/heap/analysis/agent/internal/HeapDumpReceiver.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,126 @@
+/*
+ * 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.vm.heap.analysis.agent.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+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.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.model.HeapInfo;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import com.redhat.thermostat.vm.heap.analysis.common.HistogramLoader;
+import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram;
+
+public class HeapDumpReceiver implements RequestReceiver {
+
+    private static final Logger log = LoggingUtils.getLogger(HeapDumpReceiver.class);
+
+    private final HeapDAO heapDao;
+
+    private final JMXHeapDumper jmxHeapDumper;
+    private final JMapHeapDumper jmapHeapDumper;
+
+    private final HistogramLoader histogramLoader;
+
+    public HeapDumpReceiver(HeapDAO heapDao) {
+        this(heapDao, new JMXHeapDumper(), new JMapHeapDumper(), new HistogramLoader());
+    }
+
+    HeapDumpReceiver(HeapDAO heapDao, JMXHeapDumper jmxHeapDumper, JMapHeapDumper jmapHeapDumper, HistogramLoader histogramLoader) {
+        this.heapDao = heapDao;
+        this.jmxHeapDumper = jmxHeapDumper;
+        this.jmapHeapDumper = jmapHeapDumper;
+        this.histogramLoader = histogramLoader;
+    }
+
+    @Override
+    public Response receive(Request request) {
+        String vmId = request.getParameter("vmId");
+        try {
+            File heapDumpFile = dumpHeap(vmId);
+            ObjectHistogram histogram = loadHistogram(heapDumpFile.getAbsolutePath());
+            saveHeapDumpInfo(vmId, heapDumpFile, histogram);
+            
+        } catch (IOException e) {
+            log.log(Level.SEVERE, "Unexpected IO problem while writing heap dump", e);
+            return new Response(ResponseType.ERROR);
+        } catch (HeapDumpException e) {
+            log.log(Level.SEVERE, "Unexpected problem while writing heap dump", e);
+            return new Response(ResponseType.ERROR);
+        }
+        return new Response(ResponseType.OK);
+    }
+
+    private File dumpHeap(String vmId) throws IOException, HeapDumpException {
+        File tempFile = Files.createTempFile("thermostat-", "-heapdump").toFile();
+        String tempFileName = tempFile.getAbsolutePath();
+        tempFile.delete(); // Need to delete before dumping heap, jmap does not override existing file and stop with an error.
+        dumpHeapUsingJMX(vmId, tempFileName);
+        return tempFile;
+    }
+
+    private void dumpHeapUsingJMX(String vmId, String filename) throws HeapDumpException {
+
+        try {
+            jmxHeapDumper.dumpHeap(vmId, filename);
+        } catch (HeapDumpException e) {
+            log.log(Level.WARNING, "Heap dump using JMX failed, trying jmap", e);
+            dumpHeapUsingJMap(vmId, filename);
+        }
+    }
+
+    private void dumpHeapUsingJMap(String vmId, String filename) throws HeapDumpException {
+        jmapHeapDumper.dumpHeap(vmId, filename);
+    }
+
+    private ObjectHistogram loadHistogram(String heapDumpFilename) throws IOException {
+        return histogramLoader.load(heapDumpFilename);
+    }
+
+    private void saveHeapDumpInfo(String vmId, File tempFile, ObjectHistogram histogram) throws IOException {
+        HeapInfo heapInfo = new HeapInfo(Integer.parseInt(vmId), System.currentTimeMillis());
+        heapDao.putHeapInfo(heapInfo, tempFile, histogram);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/agent/src/main/java/com/redhat/thermostat/vm/heap/analysis/agent/internal/JMXHeapDumper.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,92 @@
+/*
+ * 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.vm.heap.analysis.agent.internal;
+
+import java.io.File;
+import java.util.Properties;
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+
+import com.sun.tools.attach.VirtualMachine;
+
+class JMXHeapDumper {
+
+    private static final String CONNECTOR_ADDRESS_PROPERTY = "com.sun.management.jmxremote.localConnectorAddress";
+
+    void dumpHeap(String vmId, String filename) throws HeapDumpException {
+        try {
+            doHeapDump(vmId, filename);
+        } catch (Exception ex) {
+            throw new HeapDumpException(ex);
+        }
+    }
+
+    private void doHeapDump(String vmId, String filename) throws Exception {
+
+        VirtualMachine vm = VirtualMachine.attach(vmId);
+        String connectorAddress = getConnectorAddress(vm);
+        JMXServiceURL url = new JMXServiceURL(connectorAddress);
+
+        try (JMXConnector conn = JMXConnectorFactory.connect(url)) {
+            MBeanServerConnection mbsc = conn.getMBeanServerConnection();
+            mbsc.invoke(new ObjectName("com.sun.management:type=HotSpotDiagnostic"),
+                        "dumpHeap",
+                        new Object[] { filename, Boolean.TRUE },
+                        new String[] { String.class.getName(), boolean.class.getName() });
+        }
+    }
+
+    private String getConnectorAddress(VirtualMachine vm) throws Exception {
+
+        Properties props = vm.getAgentProperties();
+        String 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);
+        }
+        return connectorAddress;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/agent/src/main/java/com/redhat/thermostat/vm/heap/analysis/agent/internal/JMapHeapDumper.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,61 @@
+/*
+ * 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.vm.heap.analysis.agent.internal;
+
+import java.io.IOException;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.common.utils.LoggingUtils;
+
+class JMapHeapDumper {
+
+    private static final Logger log = LoggingUtils.getLogger(JMapHeapDumper.class);
+
+    void dumpHeap(String vmId, String filename) throws HeapDumpException {
+        try {
+            Process proc = Runtime.getRuntime().exec(
+                    new String[] { "jmap", "-dump:format=b,file=" + filename, vmId });
+            proc.waitFor();
+            log.info("Heap dump written to: " + filename);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+        } catch (IOException ex) {
+            throw new HeapDumpException(ex);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/agent/src/test/java/com/redhat/thermostat/vm/heap/analysis/agent/internal/ActivatorTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,96 @@
+/*
+ * 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.vm.heap.analysis.agent.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import static org.mockito.Mockito.mock;
+
+import org.junit.Test;
+import org.osgi.framework.ServiceRegistration;
+
+import com.redhat.thermostat.agent.command.RequestReceiver;
+import com.redhat.thermostat.test.StubBundleContext;
+import com.redhat.thermostat.vm.heap.analysis.agent.internal.Activator;
+import com.redhat.thermostat.vm.heap.analysis.agent.internal.HeapDumpReceiver;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+
+public class ActivatorTest {
+
+    @Test
+    public void testStartStopWithoutDependencies() {
+        StubBundleContext ctx = new StubBundleContext();
+
+        Activator activator = new Activator();
+
+        activator.start(ctx);
+
+        assertEquals(0, ctx.getAllServices().size());
+
+        activator.stop(ctx);
+
+        assertEquals(0, ctx.getAllServices().size());
+        assertEquals(0, ctx.getServiceListeners().size());
+    }
+
+    @Test
+    public void testStartStopWithDependency() throws Exception {
+        StubBundleContext ctx = new StubBundleContext();
+
+        HeapDAO heapDao = mock(HeapDAO.class);
+        ServiceRegistration registration = ctx.registerService(HeapDAO.class, heapDao, null);
+
+        Activator activator = new Activator();
+
+        activator.start(ctx);
+
+        assertTrue(ctx.isServiceRegistered(RequestReceiver.class.getName(), HeapDumpReceiver.class));
+
+        assertEquals(1, ctx.getServiceListeners().size());
+
+        activator.stop(ctx);
+
+        assertFalse(ctx.isServiceRegistered(RequestReceiver.class.getName(), HeapDumpReceiver.class));
+
+        assertEquals(0, ctx.getServiceListeners().size());
+
+        assertEquals(0, ctx.getExportedServiceCount(registration));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/agent/src/test/java/com/redhat/thermostat/vm/heap/analysis/agent/internal/HeapDumpReceiverTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,143 @@
+/*
+ * 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.vm.heap.analysis.agent.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+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.storage.model.HeapInfo;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import com.redhat.thermostat.vm.heap.analysis.common.HistogramLoader;
+import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram;
+
+public class HeapDumpReceiverTest {
+
+    private HeapDAO heapDAO;
+    private Request request;
+    private JMXHeapDumper jmxDumper;
+    private HistogramLoader histogramLoader;
+
+    private HeapDumpReceiver receiver;
+    private JMapHeapDumper jmapDumper;
+
+    @Before
+    public void setUp() {
+        heapDAO = mock(HeapDAO.class);
+
+        request = mock(Request.class);
+        when(request.getParameter("vmId")).thenReturn("123");
+        jmxDumper = mock(JMXHeapDumper.class);
+        jmapDumper = mock(JMapHeapDumper.class);
+        histogramLoader = mock(HistogramLoader.class);
+        receiver = new HeapDumpReceiver(heapDAO, jmxDumper, jmapDumper, histogramLoader);
+    }
+
+    @After
+    public void tearDown() {
+        histogramLoader = null;
+        jmapDumper = null;
+        jmxDumper = null;
+        request = null;
+        heapDAO = null;
+    }
+
+    @Test
+    public void testJMXHeapDump() throws Exception {
+
+        ObjectHistogram expectedHistogramData = mock(ObjectHistogram.class);
+        when(histogramLoader.load(anyString())).thenReturn(expectedHistogramData);
+        
+        Response response = receiver.receive(request);
+
+        assertEquals(ResponseType.OK, response.getType());
+        ArgumentCaptor<String> filename = ArgumentCaptor.forClass(String.class);
+        verify(jmxDumper).dumpHeap(eq("123"), filename.capture());
+        verify(histogramLoader).load(filename.getValue());
+        ArgumentCaptor<HeapInfo> heapInfo = ArgumentCaptor.forClass(HeapInfo.class);
+        verify(heapDAO).putHeapInfo(heapInfo.capture(), eq(new File(filename.getValue())), same(expectedHistogramData));
+        assertEquals(123, heapInfo.getValue().getVmId());
+    }
+
+    @Test
+    public void verifyFallbackWhenJMXFails() throws HeapDumpException {
+
+        doThrow(new HeapDumpException()).when(jmxDumper).dumpHeap(anyString(), anyString());
+
+        Response response = receiver.receive(request);
+
+        assertEquals(ResponseType.OK, response.getType());
+        verify(jmxDumper).dumpHeap(eq("123"), anyString());
+        
+    }
+
+    @Test
+    public void verifyResponseTypeWhenAllFails() throws HeapDumpException {
+        doThrow(new HeapDumpException()).when(jmxDumper).dumpHeap(anyString(), anyString());
+        doThrow(new HeapDumpException()).when(jmapDumper).dumpHeap(anyString(), anyString());
+        Response response = receiver.receive(request);
+
+        assertEquals(ResponseType.ERROR, response.getType());
+        
+    }
+
+    @Test
+    public void verifyResponseTypeWhenIOFails() throws HeapDumpException, IOException {
+        doThrow(new IOException()).when(histogramLoader).load(anyString());
+
+        Response response = receiver.receive(request);
+
+        assertEquals(ResponseType.ERROR, response.getType());
+        
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/pom.xml	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,163 @@
+<?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>
+    <artifactId>thermostat-vm-heap-analysis</artifactId>
+    <groupId>com.redhat.thermostat</groupId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>thermostat-vm-heap-analysis-client-core</artifactId>
+  <packaging>bundle</packaging>
+  <name>Thermostat VM Heap Analysis Core Client plugin</name>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-SymbolicName>com.redhat.thermostat.vm.heap.analysis.client.core</Bundle-SymbolicName>
+            <Export-Package>
+               com.redhat.thermostat.vm.heap.analysis.client.core,
+               com.redhat.thermostat.vm.heap.analysis.client.core.chart,
+               com.redhat.thermostat.vm.heap.analysis.client.locale
+            </Export-Package>
+            <Private-Package>
+               com.redhat.thermostat.vm.heap.analysis.client.core.internal
+            </Private-Package>
+            <Bundle-Activator>com.redhat.thermostat.vm.heap.analysis.client.core.internal.Activator</Bundle-Activator>
+            <!-- Do not autogenerate uses clauses in Manifests -->
+            <_nouses>true</_nouses>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-mockito</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-client-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-tools</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-client-command</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-test</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-vm-heap-analysis-common</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-vm-heap-analysis-command</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-vm-heap-analysis-agent</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.jfree</groupId>
+      <artifactId>jfreechart</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.sun</groupId>
+      <artifactId>tools</artifactId>
+      <scope>system</scope>
+      <systemPath>${java.home}/../lib/tools.jar</systemPath>
+    </dependency>
+    
+  </dependencies>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapDumpDetailsView.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,47 @@
+/*
+ * 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.vm.heap.analysis.client.core;
+
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.core.views.UIComponent;
+
+public abstract class HeapDumpDetailsView extends BasicView implements UIComponent {
+
+    public abstract void addSubView(String title, HeapHistogramView child);
+    public abstract void addSubView(String title, ObjectDetailsView child);
+    public abstract void removeSubView(String title);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapDumpDetailsViewProvider.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,45 @@
+/*
+ * 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.vm.heap.analysis.client.core;
+
+import com.redhat.thermostat.client.core.views.ViewProvider;
+
+public interface HeapDumpDetailsViewProvider extends ViewProvider {
+
+    @Override
+    public HeapDumpDetailsView createView();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapDumperService.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,84 @@
+/*
+ * 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.vm.heap.analysis.client.core;
+
+import com.redhat.thermostat.client.core.VmFilter;
+import com.redhat.thermostat.client.core.VmInformationService;
+import com.redhat.thermostat.client.core.controllers.VmInformationServiceController;
+import com.redhat.thermostat.client.osgi.service.AlwaysMatchFilter;
+import com.redhat.thermostat.common.ApplicationService;
+import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.vm.heap.analysis.client.core.internal.HeapDumpController;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+
+public class HeapDumperService implements VmInformationService {
+    
+    private static final int PRIORITY = PRIORITY_MEMORY_GROUP + 60;
+    private ApplicationService appService;
+    private VmMemoryStatDAO vmMemoryStatDao;
+    private HeapDAO heapDao;
+
+    private VmFilter filter = new AlwaysMatchFilter();
+
+    public HeapDumperService(ApplicationService appService, VmMemoryStatDAO vmMemoryStatDao, HeapDAO heapDao) {
+        this.vmMemoryStatDao = vmMemoryStatDao;
+        this.heapDao = heapDao;
+        this.appService = appService;
+    }
+
+    @Override
+    public VmInformationServiceController getInformationServiceController(VmRef ref) {
+        HeapViewProvider viewProvider = OSGIUtils.getInstance().getService(HeapViewProvider.class);
+        HeapDumpDetailsViewProvider detailsViewProvider = OSGIUtils.getInstance().getService(HeapDumpDetailsViewProvider.class);
+        HeapHistogramViewProvider histogramViewProvider = OSGIUtils.getInstance().getService(HeapHistogramViewProvider.class);
+        ObjectDetailsViewProvider objectDetailsViewProvider = OSGIUtils.getInstance().getService(ObjectDetailsViewProvider.class);
+        ObjectRootsViewProvider objectRootsViewProvider = OSGIUtils.getInstance().getService(ObjectRootsViewProvider.class);
+        return new HeapDumpController(vmMemoryStatDao, heapDao, ref, appService, viewProvider, detailsViewProvider, histogramViewProvider, objectDetailsViewProvider, objectRootsViewProvider);
+    }
+
+    @Override
+    public VmFilter getFilter() {
+        return filter;
+    }
+
+    @Override
+    public int getPriority() {
+        return PRIORITY;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapHistogramView.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,47 @@
+/*
+ * 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.vm.heap.analysis.client.core;
+
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.core.views.UIComponent;
+import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram;
+
+public abstract class HeapHistogramView extends BasicView implements UIComponent {
+
+    public abstract void display(ObjectHistogram histogram);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapHistogramViewProvider.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,45 @@
+/*
+ * 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.vm.heap.analysis.client.core;
+
+import com.redhat.thermostat.client.core.views.ViewProvider;
+
+public interface HeapHistogramViewProvider extends ViewProvider {
+
+    @Override
+    public HeapHistogramView createView();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapObjectUI.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,53 @@
+/*
+ * 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.vm.heap.analysis.client.core;
+
+public class HeapObjectUI {
+
+    public String objectId;
+    public String text;
+
+    public HeapObjectUI(String objectId, String text) {
+        this.objectId = objectId;
+        this.text = text;
+    }
+
+    @Override
+    public String toString() {
+        return text;
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapView.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,83 @@
+/*
+ * 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.vm.heap.analysis.client.core;
+
+import java.util.List;
+
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.core.views.UIComponent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ActionNotifier;
+import com.redhat.thermostat.vm.heap.analysis.client.core.chart.OverviewChart;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+
+public abstract class HeapView extends BasicView implements UIComponent {
+    
+    public enum HeapDumperAction {
+        DUMP_REQUESTED,
+        ANALYSE,
+        REQUEST_ABORTED
+    }
+   
+    protected final ActionNotifier<HeapDumperAction> heapDumperNotifier;
+    protected HeapView() {
+        heapDumperNotifier = new ActionNotifier<HeapDumperAction>(this);
+    }
+    
+    public void addDumperListener(ActionListener<HeapDumperAction> listener) {
+        heapDumperNotifier.addActionListener(listener);
+    }
+    
+    public void removeDumperListener(ActionListener<HeapDumperAction> listener) {
+        heapDumperNotifier.removeActionListener(listener);
+    }
+
+    abstract public void updateUsedAndCapacity(String used, String capacity);
+    /** View updates automatically based on the model */
+    abstract public void setModel(OverviewChart model);
+    abstract public void addHeapDump(HeapDump dump);
+    abstract public void clearHeapDumpList();
+    
+    abstract public void openDumpView();
+    abstract public void setChildView(BasicView childView);
+    public abstract void notifyHeapDumpComplete();
+
+    public abstract void updateHeapDumpList(List<HeapDump> heapDumps);
+
+    public abstract void displayWarning(String string);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/HeapViewProvider.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,45 @@
+/*
+ * 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.vm.heap.analysis.client.core;
+
+import com.redhat.thermostat.client.core.views.ViewProvider;
+
+public interface HeapViewProvider extends ViewProvider {
+
+    @Override
+    public HeapView createView();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/ObjectDetailsView.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,81 @@
+/*
+ * 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.vm.heap.analysis.client.core;
+
+import java.util.Collection;
+
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.core.views.UIComponent;
+import com.redhat.thermostat.common.ActionListener;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+
+public abstract class ObjectDetailsView extends BasicView implements UIComponent {
+
+    // TODO this should be some sort of aggregate view
+    // showing users 1000 instances of a class is not very useful unless we
+    // allow the user some aggregate results or allow additional sorting or
+    // filtering
+
+    public enum ObjectAction {
+        SEARCH,
+        GET_OBJECT_DETAIL,
+        SHOW_ROOT_TO_GC,
+    }
+
+    public static interface ObjectReferenceCallback {
+        /** get a list of objects that refers to this object */
+        Collection<HeapObjectUI> getReferrers(HeapObjectUI obj);
+
+        /** get a list of objects that this object refers to */
+        Collection<HeapObjectUI> getReferences(HeapObjectUI obj);
+    }
+
+    public abstract void addObjectActionListener(ActionListener<ObjectAction> listener);
+    public abstract void removeObjectActionListnener(ActionListener<ObjectAction> listener);
+
+    public abstract void addObjectReferenceCallback(ObjectReferenceCallback callback);
+    public abstract void removeObjectReferenceCallback(ObjectReferenceCallback callback);
+
+    public abstract String getSearchText();
+
+    public abstract void setMatchingObjects(Collection<HeapObjectUI> objects);
+
+    public abstract HeapObjectUI getSelectedMatchingObject();
+
+    public abstract void setObjectDetails(JavaHeapObject object);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/ObjectDetailsViewProvider.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,45 @@
+/*
+ * 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.vm.heap.analysis.client.core;
+
+import com.redhat.thermostat.client.core.views.ViewProvider;
+
+public interface ObjectDetailsViewProvider extends ViewProvider {
+
+    @Override
+    public ObjectDetailsView createView();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/ObjectRootsView.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,61 @@
+/*
+ * 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.vm.heap.analysis.client.core;
+
+import java.util.List;
+
+import com.redhat.thermostat.client.core.views.UIComponent;
+import com.redhat.thermostat.client.core.views.View;
+import com.redhat.thermostat.common.ActionListener;
+
+public interface ObjectRootsView extends View, UIComponent {
+
+    enum Action {
+        VISIBLE,
+        HIDDEN,
+        OBJECT_SELECTED,
+    }
+
+    void addActionListener(ActionListener<Action> listener);
+    void removeActionListener(ActionListener<Action> listener);
+
+    void showView();
+    void hideView();
+
+    void setPathToRoot(List<HeapObjectUI> pathToRoot);
+    void setObjectDetails(String information);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/ObjectRootsViewProvider.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,46 @@
+/*
+ * 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.vm.heap.analysis.client.core;
+
+import com.redhat.thermostat.client.core.views.ViewProvider;
+
+public interface ObjectRootsViewProvider extends ViewProvider {
+
+    @Override
+    public ObjectRootsView createView();
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/chart/OverviewChart.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,173 @@
+/*
+ * 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.vm.heap.analysis.client.core.chart;
+
+import java.awt.Color;
+import java.awt.GradientPaint;
+import java.awt.Paint;
+import java.util.Date;
+
+import javax.swing.plaf.ColorUIResource;
+
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.DateAxis;
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.axis.TickUnits;
+import org.jfree.chart.axis.ValueAxis;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.XYDifferenceRenderer;
+import org.jfree.data.RangeType;
+import org.jfree.data.time.Millisecond;
+import org.jfree.data.time.TimeSeries;
+import org.jfree.data.time.TimeSeriesCollection;
+
+import com.redhat.thermostat.client.ui.BytesTickUnit;
+
+public class OverviewChart {
+        
+    private static final ColorUIResource MAIN_BAR_BASE_COLOR = new ColorUIResource(0x4A90D9);
+
+    private static final String lock = new String("chartLock");
+
+    private TimeSeries total;
+    private TimeSeries used;
+    private String title;
+    private String xAxis;
+    private String yAxis;
+    
+    public OverviewChart(String title, String xAxis, String yAxis, String mainSeries, String secondarySeries) {
+        
+        this.title = title;
+        this.xAxis = xAxis;
+        this.yAxis = yAxis;
+        
+        total = new TimeSeries(mainSeries);
+        total.setDescription(mainSeries);
+        
+        used = new TimeSeries(secondarySeries);
+        used.setDescription(secondarySeries);
+    }
+    
+    public JFreeChart createChart(int height, Color bgColor) {
+
+        TimeSeriesCollection dataset = new TimeSeriesCollection();
+        
+        synchronized (lock) {
+            dataset.addSeries(total);
+            dataset.addSeries(used);
+        }
+        
+        JFreeChart chart = ChartFactory.createTimeSeriesChart(
+                title,
+                xAxis,
+                yAxis,
+                dataset,
+                true,  // legend
+                false,  // tool tips
+                false   // URLs
+        );
+
+        Paint paint = new GradientPaint(0, 0, MAIN_BAR_BASE_COLOR, 0, height, bgColor);
+        Paint paint2 = new GradientPaint(0, 0, Color.GREEN, 0, height, bgColor);
+
+        XYPlot plot = (XYPlot) chart.getPlot();
+        plot.setDomainPannable(true);
+        XYDifferenceRenderer r = new XYDifferenceRenderer(paint, paint2, false);
+        r.setRoundXCoordinates(true);
+        plot.setDomainCrosshairLockedOnData(true);
+        plot.setRangeCrosshairLockedOnData(true);
+        plot.setDomainCrosshairVisible(true);
+        plot.setRangeCrosshairVisible(true);
+        plot.setRenderer(r);
+
+        ValueAxis domainAxis = new DateAxis(xAxis);
+        domainAxis.setLowerMargin(0.0);
+        domainAxis.setUpperMargin(0.0);
+        plot.setDomainAxis(domainAxis);
+        plot.setForegroundAlpha(0.5f);
+        TickUnits tickUnits = new TickUnits();
+        tickUnits.add(new BytesTickUnit(1.));
+        tickUnits.add(new BytesTickUnit(10.));
+        tickUnits.add(new BytesTickUnit(100.));
+        tickUnits.add(new BytesTickUnit(1000.));
+        tickUnits.add(new BytesTickUnit(10000.));
+        tickUnits.add(new BytesTickUnit(100000.));
+        tickUnits.add(new BytesTickUnit(1000000.));
+        tickUnits.add(new BytesTickUnit(10000000.));
+        tickUnits.add(new BytesTickUnit(100000000.));
+        tickUnits.add(new BytesTickUnit(1000000000.));
+        tickUnits.add(new BytesTickUnit(10000000000.));
+        tickUnits.add(new BytesTickUnit(100000000000.));
+        tickUnits.add(new BytesTickUnit(1000000000000.));
+        NumberAxis yAxis = (NumberAxis) plot.getRangeAxis();
+        yAxis.setStandardTickUnits(tickUnits);
+        yAxis.setRangeType(RangeType.POSITIVE);
+        yAxis.setAutoRangeMinimumSize(10);
+        yAxis.setAutoRange(true);
+        return chart;
+    }
+
+    public void addData(long timeStamp, long used, long total) {
+        
+        Millisecond millisecond = new Millisecond(new Date(timeStamp));
+        synchronized (lock) {            
+            if (this.total.getValue(millisecond) == null) {
+                this.total.add(millisecond, total, false);
+                this.total.removeAgedItems(true);
+            }
+            
+            if (this.used.getValue(millisecond) == null) {
+                this.used.add(millisecond, used, false);
+                this.used.removeAgedItems(true);
+            }
+        }
+        
+    }
+
+    public void notifyListenersOfModelChange() {
+        synchronized (lock) {
+            this.total.fireSeriesChanged();
+            this.used.fireSeriesChanged();
+        }
+    }
+
+    public void setRange(int seconds) {
+        total.setMaximumItemCount(seconds);
+        used.setMaximumItemCount(seconds);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/Activator.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,94 @@
+/*
+ * 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.vm.heap.analysis.client.core.internal;
+
+import java.util.Map;
+import java.util.Objects;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+import com.redhat.thermostat.client.core.VmInformationService;
+import com.redhat.thermostat.common.ApplicationService;
+import com.redhat.thermostat.common.MultipleServiceTracker;
+import com.redhat.thermostat.common.MultipleServiceTracker.Action;
+import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumperService;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+
+public class Activator implements BundleActivator {
+
+    private MultipleServiceTracker tracker;
+    private ServiceRegistration reg;
+
+    @Override
+    public void start(final BundleContext context) throws Exception {
+        Class<?>[] deps = new Class<?>[] {
+            ApplicationService.class,
+            VmMemoryStatDAO.class,
+            HeapDAO.class,
+        };
+
+        tracker = new MultipleServiceTracker(context, deps, new Action() {
+            
+            @Override
+            public void dependenciesAvailable(Map<String, Object> services) {
+                ApplicationService appSvc = (ApplicationService) services.get(ApplicationService.class.getName());
+                Objects.requireNonNull(appSvc);
+                VmMemoryStatDAO vmMemoryStatDao = (VmMemoryStatDAO) services.get(VmMemoryStatDAO.class.getName());
+                Objects.requireNonNull(vmMemoryStatDao);
+                HeapDAO heapDao = (HeapDAO) services.get(HeapDAO.class.getName());
+                Objects.requireNonNull(heapDao);
+
+                HeapDumperService service = new HeapDumperService(appSvc, vmMemoryStatDao, heapDao);
+                reg = context.registerService(VmInformationService.class.getName(), service , null);
+            }
+
+            @Override
+            public void dependenciesUnavailable() {
+                reg.unregister();
+            }
+        });
+        tracker.open();
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        tracker.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpController.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,298 @@
+/*
+ * 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.vm.heap.analysis.client.core.internal;
+
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import com.redhat.thermostat.client.core.controllers.VmInformationServiceController;
+import com.redhat.thermostat.client.core.views.BasicView.Action;
+import com.redhat.thermostat.client.core.views.UIComponent;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ApplicationService;
+import com.redhat.thermostat.common.NotImplementedException;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.Timer.SchedulingType;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
+import com.redhat.thermostat.storage.model.HeapInfo;
+import com.redhat.thermostat.storage.model.VmMemoryStat;
+import com.redhat.thermostat.storage.model.VmMemoryStat.Generation;
+import com.redhat.thermostat.storage.model.VmMemoryStat.Space;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView.HeapDumperAction;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.chart.OverviewChart;
+import com.redhat.thermostat.vm.heap.analysis.client.locale.LocaleResources;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+
+public class HeapDumpController implements VmInformationServiceController {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private final VmMemoryStatDAO vmDao;
+    private final VmRef ref;
+    
+    private final HeapDAO heapDAO;
+        
+    private HeapView view;
+    private final Timer timer;
+    
+    private OverviewChart model;
+    private ApplicationService appService;
+    private HeapDumpDetailsViewProvider detailsViewProvider;
+    private HeapHistogramViewProvider histogramViewProvider;
+    private ObjectDetailsViewProvider objectDetailsViewProvider;
+    private ObjectRootsViewProvider objectRootsViewProvider;
+
+    public HeapDumpController(final VmMemoryStatDAO vmMemoryStatDao,
+            final HeapDAO heapDao, final VmRef ref,
+            final ApplicationService appService, HeapViewProvider viewProvider,
+            HeapDumpDetailsViewProvider detailsViewProvider,
+            HeapHistogramViewProvider histogramProvider,
+            ObjectDetailsViewProvider objectDetailsProvider,
+            ObjectRootsViewProvider objectRootsProvider) {
+        this(vmMemoryStatDao, heapDao, ref, appService, viewProvider,
+                detailsViewProvider, histogramProvider, objectDetailsProvider,
+                objectRootsProvider, new HeapDumper(ref));
+    }
+
+    HeapDumpController(final VmMemoryStatDAO vmMemoryStatDao,
+            final HeapDAO heapDao, final VmRef ref,
+            final ApplicationService appService, HeapViewProvider viewProvider,
+            HeapDumpDetailsViewProvider detailsViewProvider,
+            HeapHistogramViewProvider histogramProvider,
+            ObjectDetailsViewProvider objectDetailsProvider,
+            ObjectRootsViewProvider objectRootsProvider,
+            final HeapDumper heapDumper) {
+        this.objectDetailsViewProvider = objectDetailsProvider;
+        this.objectRootsViewProvider = objectRootsProvider;
+        this.histogramViewProvider = histogramProvider;
+        this.detailsViewProvider = detailsViewProvider;
+        this.appService = appService;
+        this.ref = ref;
+        this.vmDao = vmMemoryStatDao;
+        this.heapDAO = heapDao;
+        
+        model = new OverviewChart(
+                    translator.localize(LocaleResources.HEAP_CHART_TITLE),
+                    translator.localize(LocaleResources.HEAP_CHART_TIME_AXIS),
+                    translator.localize(LocaleResources.HEAP_CHART_HEAP_AXIS),
+                    translator.localize(LocaleResources.HEAP_CHART_CAPACITY),
+                    translator.localize(LocaleResources.HEAP_CHART_USED));
+        
+        timer = appService.getTimerFactory().createTimer();
+        timer.setAction(new HeapOverviewDataCollector());
+        
+        timer.setInitialDelay(0);
+        timer.setDelay(1000);
+        model.setRange(3600);
+        timer.setTimeUnit(TimeUnit.MILLISECONDS);
+        timer.setSchedulingType(SchedulingType.FIXED_RATE);
+        
+        view = viewProvider.createView();
+        view.setModel(model);
+        
+        HeapDump dump = null;
+        view.clearHeapDumpList();
+        Collection<HeapInfo> infos = heapDAO.getAllHeapInfo(ref);
+        for (HeapInfo info : infos) {
+            dump = new HeapDump(info, heapDAO);
+            view.addHeapDump(dump);
+        }
+        
+        // check if we were reading some of the dumps
+        dump = (HeapDump) appService.getApplicationCache().getAttribute(ref);
+        if (dump != null && infos.contains(dump.getInfo())) {
+            showHeapDumpDetails(dump);
+        }
+        
+        view.addActionListener(new ActionListener<Action>() {            
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                switch (actionEvent.getActionId()) {
+                case HIDDEN:
+                    timer.stop();
+                    break;
+                
+                case VISIBLE:                    
+                    timer.start();
+                    break;
+
+                default:
+                    throw new NotImplementedException("unknown event: " + actionEvent.getActionId());
+                }
+            }
+        });
+
+        view.addDumperListener(new ActionListener<HeapView.HeapDumperAction>() {
+            @Override
+            public void actionPerformed(ActionEvent<HeapDumperAction> actionEvent) {
+                HeapDump dump = null;
+                switch (actionEvent.getActionId()) {
+                case DUMP_REQUESTED:
+                    requestDump(heapDumper);
+                    break;
+                case ANALYSE:
+                    dump = (HeapDump) actionEvent.getPayload();
+                    analyseDump(dump);
+                    break;
+                default:
+                    break;
+                }
+            }
+        });
+    }
+
+    private void requestDump(final HeapDumper heapDumper) {
+        appService.getApplicationExecutor().execute(new Runnable() {
+            
+            @Override
+            public void run() {
+                try {
+                    heapDumper.dump();
+                    view.notifyHeapDumpComplete();
+                } catch (CommandException e) {
+                    view.displayWarning(e.getMessage());
+                }
+            }
+        });
+    }
+
+    private void analyseDump(final HeapDump dump) {
+        appService.getApplicationExecutor().execute(new Runnable() {
+            
+            @Override
+            public void run() {
+                showHeapDumpDetails(dump);
+                appService.getApplicationCache().addAttribute(ref, dump);
+            }
+        });
+    }
+
+    private void showHeapDumpDetails(HeapDump dump) {
+        HeapDumpDetailsController controller = new HeapDumpDetailsController(
+                appService, detailsViewProvider, histogramViewProvider,
+                objectDetailsViewProvider, objectRootsViewProvider);
+        controller.setDump(dump);
+        view.setChildView(controller.getView());
+        view.openDumpView();
+    }
+
+    @Override
+    public UIComponent getView() {
+        return (UIComponent) view;
+    }
+
+    @Override
+    public String getLocalizedName() {
+        return translator.localize(LocaleResources.HEAP_SECTION_TITLE);
+    }
+
+    class HeapOverviewDataCollector implements Runnable {
+
+        private long desiredUpdateTimeStamp = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1);
+
+        @Override
+        public void run() {
+            checkForHeapDumps();
+            updateMemoryChartAndDisplay();
+        }
+
+        private void checkForHeapDumps() {
+            Collection<HeapInfo> heapInfos = heapDAO.getAllHeapInfo(ref);
+            List<HeapDump> heapDumps = new ArrayList<HeapDump>(heapInfos.size());
+            for (HeapInfo heapInfo : heapInfos) {
+                heapDumps.add(new HeapDump(heapInfo, heapDAO));
+            }
+            view.updateHeapDumpList(heapDumps);
+        }
+
+        private void updateMemoryChartAndDisplay() {
+            List<VmMemoryStat> vmInfo = null;
+            vmInfo = vmDao.getLatestVmMemoryStats(ref, desiredUpdateTimeStamp);
+
+            for (VmMemoryStat memoryStats: vmInfo) {
+                long used = 0l;
+                long capacity = 0l;
+                Generation[] generations = memoryStats.getGenerations();
+                for (Generation generation : generations) {
+                    
+                    // non heap
+                    if (generation.getName().equals("perm")) {
+                        continue;
+                    }
+                    
+                    Space[] spaces = generation.getSpaces();
+                    for (Space space: spaces) {
+                        used += space.getUsed();
+                        capacity += space.getCapacity();
+                    }
+                }
+                model.addData(memoryStats.getTimeStamp(), used, capacity);
+                
+                NumberFormat formatter = DecimalFormat.getInstance();
+
+                double res = Scale.convertTo(Scale.B, used);
+                String _used = formatter.format(res) + " " + Scale.B;
+                
+                res = Scale.convertTo(Scale.B, capacity);
+                String _capacity= formatter.format(capacity) + " " + Scale.B;
+                
+                view.updateUsedAndCapacity(_used, _capacity);
+                desiredUpdateTimeStamp = Math.max(desiredUpdateTimeStamp, memoryStats.getTimeStamp());
+            }
+
+            model.notifyListenersOfModelChange();
+        }
+
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpDetailsController.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,102 @@
+/*
+ * 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.vm.heap.analysis.client.core.internal;
+
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.common.ApplicationService;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.locale.LocaleResources;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+
+public class HeapDumpDetailsController {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private static final Logger log = LoggingUtils.getLogger(HeapDumpDetailsController.class);
+
+    private final ApplicationService appService;
+
+    private HeapDumpDetailsView view;
+    private HeapDump heapDump;
+    private HeapHistogramViewProvider histogramViewProvider;
+    private ObjectDetailsViewProvider objectDetailsViewProvider;
+    private ObjectRootsViewProvider objectRootsViewProvider;
+
+    public HeapDumpDetailsController(ApplicationService appService, HeapDumpDetailsViewProvider viewProvider, HeapHistogramViewProvider histogramProvider, ObjectDetailsViewProvider objectDetailsProvider, ObjectRootsViewProvider objectRootsProvider) {
+        this.appService = appService;
+        this.histogramViewProvider = histogramProvider;
+        this.objectDetailsViewProvider = objectDetailsProvider;
+        this.objectRootsViewProvider = objectRootsProvider;
+        view = viewProvider.createView();
+    }
+
+    public void setDump(HeapDump dump) {
+        this.heapDump = dump;
+        try {
+            HeapHistogramView heapHistogramView = histogramViewProvider.createView();
+            heapHistogramView.display(heapDump.getHistogram());
+            String title = translator.localize(LocaleResources.HEAP_DUMP_SECTION_HISTOGRAM);
+            view.addSubView(title, heapHistogramView);
+        } catch (IOException e) {
+            log.log(Level.SEVERE, "unexpected error while reading heap dump", e);
+        }
+
+        ObjectDetailsController controller = new ObjectDetailsController(appService, dump, objectDetailsViewProvider, objectRootsViewProvider);
+        ObjectDetailsView detailsView = controller.getView();
+        view.addSubView(translator.localize(LocaleResources.HEAP_DUMP_SECTION_OBJECT_BROWSER), detailsView);
+
+        // do a dummy search right now to prep the index
+        heapDump.searchObjects("A_RANDOM_PATTERN", 1);
+    }
+
+    public BasicView getView() {
+        return view;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumper.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,84 @@
+/*
+ * 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.vm.heap.analysis.client.core.internal;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+
+import com.redhat.thermostat.common.cli.Command;
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandContextFactory;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleArguments;
+import com.redhat.thermostat.common.dao.VmRef;
+
+public class HeapDumper {
+    
+    private static final String HEAP_DUMP_COMMAND = "dump-heap";
+    private static final String HOST_ID_ARGUMENT = "hostId";
+    private static final String VM_ID_ARGUMENT = "vmId";
+    
+    private Command heapDumpCommand;
+    private CommandContext commandCtx;
+    private VmRef ref;
+    
+    public HeapDumper(VmRef ref) {
+        this.ref = ref;
+        BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext();
+        CommandContextFactory ctxFactory = new CommandContextFactory(context);
+        init(ctxFactory);
+    }
+    
+    HeapDumper(VmRef ref, CommandContextFactory ctxFactory) {
+        this.ref = ref;
+        init(ctxFactory);
+    }
+    
+    private void init(CommandContextFactory ctxFactory) {
+        // Setup heap dump command
+        heapDumpCommand = ctxFactory.getCommandRegistry().getCommand(HEAP_DUMP_COMMAND);
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument(HOST_ID_ARGUMENT, ref.getAgent().getStringID());
+        args.addArgument(VM_ID_ARGUMENT, ref.getStringID());
+        commandCtx = ctxFactory.createContext(args);
+    }
+    
+    public void dump() throws CommandException {
+        heapDumpCommand.run(commandCtx);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/Histogram.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,62 @@
+/*
+ * 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.vm.heap.analysis.client.core.internal;
+
+import java.util.List;
+
+public class Histogram {
+
+    private String[] header;
+    
+    private List<Object[]> data;
+    
+    Histogram(String[] header) {
+        this.header = header;
+    }
+    
+    public String[] getHistogramColums() {
+        return header;
+    }
+
+    void setData(List<Object[]> data) {
+        this.data = data;
+    }
+
+   public List<Object[]> getData() {
+    return data;
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/ObjectDetailsController.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,207 @@
+/*
+ * 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.vm.heap.analysis.client.core.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.List;
+
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ApplicationService;
+import com.redhat.thermostat.common.NotImplementedException;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapObjectUI;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsView.ObjectAction;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsView.ObjectReferenceCallback;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+import com.sun.tools.hat.internal.model.JavaClass;
+import com.sun.tools.hat.internal.model.JavaField;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+import com.sun.tools.hat.internal.model.JavaHeapObjectVisitor;
+
+public class ObjectDetailsController {
+
+    private ApplicationService appService;
+    private HeapDump heapDump;
+    private ObjectDetailsView view;
+    private ObjectRootsViewProvider viewProvider;
+
+    public ObjectDetailsController(ApplicationService appService, HeapDump heapDump, ObjectDetailsViewProvider viewProvider, ObjectRootsViewProvider rootsViewProvider) {
+        this.appService = appService;
+        this.heapDump = heapDump;
+        this.viewProvider = rootsViewProvider;
+
+        view = viewProvider.createView();
+        addListenersToView();
+    }
+
+    private void addListenersToView() {
+
+        view.addObjectActionListener(new ActionListener<ObjectAction>() {
+            @Override
+            public void actionPerformed(ActionEvent<ObjectAction> actionEvent) {
+                switch (actionEvent.getActionId()) {
+                case SEARCH:
+                    searchForObject();
+                    break;
+                case GET_OBJECT_DETAIL:
+                    showObjectInfo();
+                    break;
+                case SHOW_ROOT_TO_GC:
+                    HeapObjectUI heapObj = (HeapObjectUI) actionEvent.getPayload();
+                    showPathToGC(heapObj);
+                    break;
+                default:
+                    throw new NotImplementedException("unknown action fired by " + actionEvent.getSource());
+                }
+
+            }
+        });
+
+        view.addObjectReferenceCallback(new ObjectReferenceCallback() {
+            @Override
+            public Collection<HeapObjectUI> getReferrers(HeapObjectUI obj) {
+                JavaHeapObject heapObject = heapDump.findObject(obj.objectId);
+
+                @SuppressWarnings("unchecked")
+                Enumeration<JavaHeapObject> referrers = heapObject.getReferers();
+
+                List<HeapObjectUI> objects = new ArrayList<>();
+                while (referrers.hasMoreElements()) {
+                    heapObject = referrers.nextElement();
+                    objects.add(new HeapObjectUI(heapObject.getIdString(), PrintObjectUtils.objectToString(heapObject)));
+                }
+                return objects;
+            }
+
+            @Override
+            public Collection<HeapObjectUI> getReferences(HeapObjectUI obj) {
+                final JavaHeapObject heapObject = heapDump.findObject(obj.objectId);
+
+                final List<JavaHeapObject> references = new ArrayList<>();
+
+                JavaHeapObjectVisitor v = new JavaHeapObjectVisitor() {
+
+                    @Override
+                    public void visit(JavaHeapObject other) {
+                        references.add(other);
+                    }
+
+                    @Override
+                    public boolean mightExclude() {
+                        /* we never return true in exclude */
+                        return false;
+                    }
+
+                    @Override
+                    public boolean exclude(JavaClass clazz, JavaField f) {
+                        /* visit every field in every java class */
+                        return false;
+                    }
+                };
+
+                heapObject.visitReferencedObjects(v);
+
+                List<HeapObjectUI> objects = new ArrayList<>();
+                for (JavaHeapObject ref: references) {
+                    objects.add(new HeapObjectUI(ref.getIdString(), PrintObjectUtils.objectToString(ref)));
+                }
+                return objects;
+            }
+        });
+    }
+
+    private void searchForObject() {
+        String searchText = view.getSearchText();
+        if (searchText == null || searchText.trim().isEmpty()) {
+            return;
+        }
+
+        final int maxResults = computeResultLimit(searchText);
+
+        if (!searchText.contains("*") && !searchText.contains("?")) {
+            searchText = "*" + searchText + "*";
+        }
+
+        final String wildcardQuery = searchText;
+
+        appService.getApplicationExecutor().execute(new Runnable() {
+
+            @Override
+            public void run() {
+                Collection<String> objectIds = heapDump.searchObjects(wildcardQuery, maxResults);
+
+                List<HeapObjectUI> toDisplay = new ArrayList<>();
+                for (String id: objectIds) {
+                    JavaHeapObject heapObject = heapDump.findObject(id);
+                    toDisplay.add(new HeapObjectUI(id, PrintObjectUtils.objectToString(heapObject)));
+                }
+                view.setMatchingObjects(toDisplay);
+            }
+        });
+
+    }
+
+    private int computeResultLimit(String searchText) {
+        return Math.min(1000, searchText.length() * 100);
+    }
+
+    private void showObjectInfo() {
+        HeapObjectUI matchingObject = view.getSelectedMatchingObject();
+        if (matchingObject == null) {
+            return;
+        }
+        String objectId = matchingObject.objectId;
+        JavaHeapObject object = heapDump.findObject(objectId);
+        view.setObjectDetails(object);
+    }
+
+    private void showPathToGC(HeapObjectUI targetObject) {
+        JavaHeapObject heapObject = heapDump.findObject(targetObject.objectId);
+
+        ObjectRootsController controller = new ObjectRootsController(heapDump, heapObject, viewProvider);
+        controller.show();
+    }
+
+    public ObjectDetailsView getView() {
+        return view;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/ObjectRootsController.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,132 @@
+/*
+ * 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.vm.heap.analysis.client.core.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.NotImplementedException;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapObjectUI;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsView.Action;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.locale.LocaleResources;
+import com.redhat.thermostat.vm.heap.analysis.command.FindRoot;
+import com.redhat.thermostat.vm.heap.analysis.command.HeapPath;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+
+public class ObjectRootsController {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private final ObjectRootsView view;
+
+    private final HeapDump heapDump;
+    private final JavaHeapObject heapObject;
+    private final FindRoot rootFinder;
+
+    public ObjectRootsController(HeapDump dump, JavaHeapObject heapObject, ObjectRootsViewProvider viewProvider) {
+        this(dump, heapObject, new FindRoot(), viewProvider);
+    }
+
+    public ObjectRootsController(HeapDump dump, JavaHeapObject heapObject, FindRoot findRoot, ObjectRootsViewProvider viewProvider) {
+        this.heapDump = dump;
+        this.heapObject = heapObject;
+        this.rootFinder = findRoot;
+
+        view = viewProvider.createView();
+
+        view.addActionListener(new ActionListener<ObjectRootsView.Action>() {
+
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                switch (actionEvent.getActionId()) {
+                case VISIBLE:
+                    view.showView();
+                    break;
+                case HIDDEN:
+                    view.hideView();
+                    break;
+                case OBJECT_SELECTED:
+                    HeapObjectUI obj = (HeapObjectUI) actionEvent.getPayload();
+                    showObjectDetails(obj);
+                    break;
+                default:
+                    throw new NotImplementedException("unexpected action " +
+                            actionEvent.getActionId() + " recieved by " + ObjectRootsController.this.getClass().getName());
+                }
+
+            }
+        });
+    }
+
+    private void showObjectDetails(HeapObjectUI uiObject) {
+        JavaHeapObject obj = heapDump.findObject(uiObject.objectId);
+        String text = translator.localize(LocaleResources.COMMAND_OBJECT_INFO_OBJECT_ID) + " " + obj.getIdString() + "\n" +
+                translator.localize(LocaleResources.COMMAND_OBJECT_INFO_TYPE) + " " + obj.getClazz().getName() + "\n" +
+                translator.localize(LocaleResources.COMMAND_OBJECT_INFO_SIZE) + " " + String.valueOf(obj.getSize()) + " bytes" + "\n" +
+                translator.localize(LocaleResources.COMMAND_OBJECT_INFO_HEAP_ALLOCATED) + " " + String.valueOf(obj.isHeapAllocated()) + "\n";
+
+        if (obj.getRoot() != null) {
+            text = text + obj.getRoot().getDescription();
+        }
+        view.setObjectDetails(text);
+    }
+
+
+    public void show() {
+        Collection<HeapPath<JavaHeapObject>> paths = rootFinder.findShortestPathsToRoot(heapObject, false);
+        Iterator<HeapPath<JavaHeapObject>> iter = paths.iterator();
+        if (iter.hasNext()) {
+            HeapPath<JavaHeapObject> pathToRoot = iter.next();
+
+            List<HeapObjectUI> path = new ArrayList<>();
+            for (JavaHeapObject heapObj : pathToRoot) {
+                path.add(new HeapObjectUI(heapObj.getIdString(), PrintObjectUtils.objectToString(heapObj)));
+            }
+            view.setPathToRoot(path);
+        }
+        view.showView();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/PrintObjectUtils.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,46 @@
+/*
+ * 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.vm.heap.analysis.client.core.internal;
+
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+
+public class PrintObjectUtils {
+
+    public static String objectToString(JavaHeapObject obj) {
+        return obj.getClazz().getName() + "@" + obj.getIdString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/locale/LocaleResources.java	Wed Dec 12 15:52:00 2012 -0500
@@ -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.vm.heap.analysis.client.locale;
+
+import com.redhat.thermostat.common.locale.Translate;
+
+public enum LocaleResources {
+    COMMAND_OBJECT_INFO_OBJECT_ID,
+    COMMAND_OBJECT_INFO_TYPE,
+    COMMAND_OBJECT_INFO_SIZE,
+    COMMAND_OBJECT_INFO_HEAP_ALLOCATED,
+    
+    HEAP_SECTION_TITLE,
+    HEAP_OVERVIEW_TITLE,
+    HEAP_CHART_TITLE,
+    HEAP_CHART_TIME_AXIS,
+    HEAP_CHART_HEAP_AXIS,
+    HEAP_CHART_CAPACITY,
+    HEAP_CHART_USED,
+    
+    HEAP_DUMP_SECTION_HISTOGRAM,
+    HEAP_DUMP_SECTION_OBJECT_BROWSER,
+    
+    HEAP_DUMP_CLASS_USAGE,
+    HEAP_DUMP_HISTOGRAM_COLUMN_CLASS,
+    HEAP_DUMP_HISTOGRAM_COLUMN_INSTANCES,
+    HEAP_DUMP_HISTOGRAM_COLUMN_SIZE,
+    
+    HEAP_DUMP_OBJECT_BROWSE_SEARCH_HINT,
+    HEAP_DUMP_OBJECT_BROWSE_SEARCH_PATTERN_HELP,
+    HEAP_DUMP_OBJECT_BROWSE_SEARCH_LABEL,
+    HEAP_DUMP_OBJECT_BROWSE_REFERRERS,
+    HEAP_DUMP_OBJECT_BROWSE_REFERENCES,
+    HEAP_DUMP_OBJECT_FIND_ROOT,
+    
+    OBJECT_ROOTS_VIEW_TITLE,
+    ;
+
+    static final String RESOURCE_BUNDLE = "com.redhat.thermostat.vm.heap.analysis.client.locale.strings";
+
+    public static Translate<LocaleResources> createLocalizer() {
+        return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/main/resources/com/redhat/thermostat/vm/heap/analysis/client/locale/strings.properties	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,29 @@
+COMMAND_OBJECT_INFO_OBJECT_ID = Object ID:
+COMMAND_OBJECT_INFO_TYPE = Type:
+COMMAND_OBJECT_INFO_SIZE = Size:
+COMMAND_OBJECT_INFO_HEAP_ALLOCATED = Heap allocated:
+
+HEAP_SECTION_TITLE = Heap Analyzer
+HEAP_OVERVIEW_TITLE = Heap Usage Overview
+HEAP_CHART_TITLE = Used Heap vs. Heap Capacity
+HEAP_CHART_TIME_AXIS = Time
+HEAP_CHART_HEAP_AXIS = Heap
+HEAP_CHART_CAPACITY = Heap Capacity
+HEAP_CHART_USED = Used Heap
+
+HEAP_DUMP_SECTION_HISTOGRAM = Histogram
+HEAP_DUMP_SECTION_OBJECT_BROWSER = Object Browser
+
+HEAP_DUMP_CLASS_USAGE = Classes Usage
+HEAP_DUMP_HISTOGRAM_COLUMN_CLASS = Class
+HEAP_DUMP_HISTOGRAM_COLUMN_INSTANCES = Instances
+HEAP_DUMP_HISTOGRAM_COLUMN_SIZE = Size (in bytes)
+
+HEAP_DUMP_OBJECT_BROWSE_SEARCH_HINT = Search for objects by class name (either a partial class name or a wildcard pattern)
+HEAP_DUMP_OBJECT_BROWSE_SEARCH_PATTERN_HELP = Either a partial class name ("Button" will find "javax.swing.JButton") or a wildcard pattern ("*JButton*" will find "javax.swing.JButtonBeanInfo")
+HEAP_DUMP_OBJECT_BROWSE_SEARCH_LABEL = Search for Object
+HEAP_DUMP_OBJECT_BROWSE_REFERRERS = Referrers
+HEAP_DUMP_OBJECT_BROWSE_REFERENCES = References
+HEAP_DUMP_OBJECT_FIND_ROOT = Find Root
+
+OBJECT_ROOTS_VIEW_TITLE = Object Roots
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/ActivatorTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,94 @@
+/*
+ * 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.vm.heap.analysis.client.core.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.client.core.VmInformationService;
+import com.redhat.thermostat.common.ApplicationService;
+import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
+import com.redhat.thermostat.test.StubBundleContext;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumperService;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+
+public class ActivatorTest {
+    
+    @Test
+    public void verifyActivatorDoesNotRegisterServiceOnMissingDeps() throws Exception {
+        StubBundleContext context = new StubBundleContext();
+
+        Activator activator = new Activator();
+
+        activator.start(context);
+
+        assertEquals(0, context.getAllServices().size());
+        assertNotSame(1, context.getServiceListeners().size());
+
+        activator.stop(context);
+
+        assertEquals(0, context.getServiceListeners().size());
+    }
+
+    @Test
+    public void verifyActivatorRegistersServices() throws Exception {
+        StubBundleContext context = new StubBundleContext();
+        VmMemoryStatDAO vmMemoryStatDAO = mock(VmMemoryStatDAO.class);
+        HeapDAO heapDAO = mock(HeapDAO.class);
+        ApplicationService appSvc = mock(ApplicationService.class);
+
+        context.registerService(VmMemoryStatDAO.class, vmMemoryStatDAO, null);
+        context.registerService(HeapDAO.class, heapDAO, null);
+        context.registerService(ApplicationService.class, appSvc, null);
+
+        Activator activator = new Activator();
+
+        activator.start(context);
+
+        assertTrue(context.isServiceRegistered(VmInformationService.class.getName(), HeapDumperService.class));
+
+        activator.stop(context);
+
+        assertEquals(0, context.getServiceListeners().size());
+        assertEquals(3, context.getAllServices().size());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpControllerTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,469 @@
+/*
+ * 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.vm.heap.analysis.client.core.internal;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ApplicationCache;
+import com.redhat.thermostat.common.ApplicationService;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.TimerFactory;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.storage.model.HeapInfo;
+import com.redhat.thermostat.storage.model.VmMemoryStat;
+import com.redhat.thermostat.storage.model.VmMemoryStat.Generation;
+import com.redhat.thermostat.storage.model.VmMemoryStat.Space;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView.HeapDumperAction;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+
+public class HeapDumpControllerTest {
+    private static int TIMEOUT_MS = 1000;
+    
+    private ActionListener<HeapView.Action> actionListener;
+    private ActionListener<HeapView.HeapDumperAction> heapDumperListener;
+
+    private Timer timer;
+
+    private HeapDAO heapDao;
+    private VmMemoryStatDAO vmDao;
+    private HeapView view;
+    private HeapDumpDetailsView detailsView;
+
+    @SuppressWarnings("unused")
+    private HeapDumpController controller;
+    private HeapDumper heapDumper;
+    private ApplicationService appService;
+    private ArgumentCaptor<Runnable> timerActionCaptor;
+
+    private HeapViewProvider viewProvider;
+    private HeapDumpDetailsViewProvider detailsViewProvider;
+    private HeapHistogramViewProvider histogramProvider;
+    private ObjectDetailsViewProvider objectDetailsProvider;
+    private ObjectRootsViewProvider objectRootsProvider;
+
+    @Before
+    public void setUp() {
+        heapDao = mock(HeapDAO.class);
+        vmDao = mock(VmMemoryStatDAO.class);
+        appService = mock(ApplicationService.class);
+        heapDumper = mock(HeapDumper.class);
+
+        setUpView();
+    }
+
+    private void setUpTimers() {
+        timer = mock(Timer.class);
+        timerActionCaptor = ArgumentCaptor.forClass(Runnable.class);
+        doNothing().when(timer).setAction(timerActionCaptor.capture());
+
+        TimerFactory timerFactory = mock(TimerFactory.class);
+        when(timerFactory.createTimer()).thenReturn(timer);
+        when(appService.getTimerFactory()).thenReturn(timerFactory);
+    }
+
+    private void setUpView() {
+        view = mock(HeapView.class);
+        viewProvider = mock(HeapViewProvider.class);
+        when(viewProvider.createView()).thenReturn(view);
+
+        detailsViewProvider = mock(HeapDumpDetailsViewProvider.class);
+        detailsView = mock(HeapDumpDetailsView.class);
+        when(detailsViewProvider.createView()).thenReturn(detailsView);
+
+        HeapHistogramView histogramView = mock(HeapHistogramView.class);
+        histogramProvider = mock(HeapHistogramViewProvider.class);
+        when(histogramProvider.createView()).thenReturn(histogramView);
+
+        ObjectDetailsView objectView = mock(ObjectDetailsView.class);
+        objectDetailsProvider = mock(ObjectDetailsViewProvider.class);
+        when(objectDetailsProvider.createView()).thenReturn(objectView);
+
+        ObjectRootsView objectRootsView = mock(ObjectRootsView.class);
+        objectRootsProvider = mock(ObjectRootsViewProvider.class);
+        when(objectRootsProvider.createView()).thenReturn(objectRootsView);
+    }
+    
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private void setUpListeners() {        
+        ArgumentCaptor<ActionListener> viewArgumentCaptor1 = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addActionListener(viewArgumentCaptor1.capture());
+        
+        ArgumentCaptor<ActionListener> viewArgumentCaptor2 = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addDumperListener(viewArgumentCaptor2.capture());
+        
+        createController();
+        
+        actionListener = viewArgumentCaptor1.getValue();
+        heapDumperListener = viewArgumentCaptor2.getValue();
+    }
+    
+    private void createController() {
+        ApplicationCache cache = mock(ApplicationCache.class);
+        when(appService.getApplicationCache()).thenReturn(cache);
+        setUpTimers();
+
+        HostRef hostRef = mock(HostRef.class);
+        when(hostRef.getAgentId()).thenReturn("agent-id");
+
+        VmRef ref = mock(VmRef.class);
+        when(ref.getIdString()).thenReturn("vm-id");
+        when(ref.getAgent()).thenReturn(hostRef);
+
+        controller = new HeapDumpController(vmDao, heapDao, ref, appService,
+                viewProvider, detailsViewProvider, histogramProvider,
+                objectDetailsProvider, objectRootsProvider, heapDumper);
+    }
+    
+    @After
+    public void tearDown() {
+        controller = null;
+        vmDao = null;
+        heapDao = null;
+        viewProvider = null;
+        detailsViewProvider = null;
+        histogramProvider = null;
+        objectDetailsProvider = null;
+        objectRootsProvider = null;
+        appService = null;
+    }
+
+    @Test
+    public void testTimerStartOnViewVisible() {
+
+        setUpListeners();
+
+        actionListener.actionPerformed(new ActionEvent<>(view,
+                HeapView.Action.VISIBLE));
+        verify(timer).start();
+    }
+
+    @Test
+    public void testTimerStopsOnViewHidden() {
+
+        setUpListeners();
+
+        actionListener.actionPerformed(new ActionEvent<>(view,
+                HeapView.Action.HIDDEN));
+        verify(timer).stop();
+    }
+
+    @Test
+    public void testNotAddHeapDumpsAtStartupWhenNoDumps() {
+
+        when(heapDao.getAllHeapInfo(any(VmRef.class))).thenReturn(
+                new ArrayList<HeapInfo>());
+
+        createController();
+
+        verify(view, times(0)).addHeapDump(any(HeapDump.class));
+    }
+
+    @Test
+    public void testAddHeapDumpsAtStartupWhenDumpsAreThere() {
+        HeapInfo info1 = mock(HeapInfo.class);
+        HeapInfo info2 = mock(HeapInfo.class);
+        Collection<HeapInfo> infos = new ArrayList<HeapInfo>();
+        infos.add(info1);
+        infos.add(info2);
+        
+        when(heapDao.getAllHeapInfo(any(VmRef.class))).thenReturn(infos);
+
+        createController();
+        
+        verify(view, times(2)).addHeapDump(any(HeapDump.class));
+    }
+    
+    @Test
+    public void testOpenDumpCalledWhenPreviousDump() {
+
+        setUpTimers();
+        HeapDump dump = mock(HeapDump.class);
+        
+        HeapInfo info1 = mock(HeapInfo.class);
+        when(dump.getInfo()).thenReturn(info1);
+        
+        HeapInfo info2 = mock(HeapInfo.class);
+        Collection<HeapInfo> infos = new ArrayList<HeapInfo>();
+        infos.add(info1);
+        infos.add(info2);
+        
+        when(heapDao.getAllHeapInfo(any(VmRef.class))).thenReturn(infos);
+        
+        ApplicationCache cache = mock(ApplicationCache.class);
+        when(cache.getAttribute(any(VmRef.class))).thenReturn(dump);
+        when(appService.getApplicationCache()).thenReturn(cache);
+        VmRef ref = mock(VmRef.class);
+        controller = new HeapDumpController(vmDao, heapDao, ref, appService,
+                viewProvider, detailsViewProvider, histogramProvider,
+                objectDetailsProvider, objectRootsProvider, heapDumper);
+        
+        verify(view, times(1)).setChildView(any(HeapView.class));
+        verify(view, times(1)).openDumpView();
+    }
+    
+    @Test
+    public void testNotOpenDumpCalledWhenNoPreviousDump() {
+
+        setUpTimers();
+        HeapInfo info1 = mock(HeapInfo.class);        
+        HeapInfo info2 = mock(HeapInfo.class);
+        Collection<HeapInfo> infos = new ArrayList<HeapInfo>();
+        infos.add(info1);
+        infos.add(info2);
+        
+        when(heapDao.getAllHeapInfo(any(VmRef.class))).thenReturn(infos);
+        
+        ApplicationCache cache = mock(ApplicationCache.class);
+        when(cache.getAttribute(any(VmRef.class))).thenReturn(null);
+
+        when(appService.getApplicationCache()).thenReturn(cache);
+        VmRef ref = mock(VmRef.class);
+        controller = new HeapDumpController(vmDao, heapDao, ref, appService,
+                viewProvider, detailsViewProvider, histogramProvider,
+                objectDetailsProvider, objectRootsProvider, heapDumper);
+        
+        verify(view, times(0)).openDumpView();
+    }
+
+    @Test
+    public void testRequestHeapDump() throws CommandException, InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        mockExecutorService(latch);
+        setUpListeners();
+
+        heapDumperListener.actionPerformed(new ActionEvent<HeapDumperAction>(view, HeapDumperAction.DUMP_REQUESTED));
+        latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+
+        verify(heapDumper).dump();
+        verify(view).notifyHeapDumpComplete();
+    }
+
+    @Test
+    public void testRequestHeapDumpFails() throws CommandException, InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final String errMessage = "Error dumping heap (agent: agent-id, vm: vm-id)";
+        mockExecutorService(latch);
+        setUpListeners();
+        
+        doThrow(new CommandException(errMessage)).when(heapDumper).dump();
+        heapDumperListener.actionPerformed(new ActionEvent<HeapDumperAction>(view, HeapDumperAction.DUMP_REQUESTED));
+        latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        
+        verify(heapDumper).dump();
+        verify(view).displayWarning(errMessage);
+    }
+
+    private void mockExecutorService(final CountDownLatch latch) {
+        ExecutorService executor = mock(ExecutorService.class);
+        doAnswer(new Answer<Object>() {
+    
+            @Override
+            public Object answer(InvocationOnMock invocation) throws Throwable {
+                Runnable runnable = (Runnable) invocation.getArguments()[0];
+                runnable.run();
+                latch.countDown();
+                return null;
+            }
+        }).when(executor).execute(any(Runnable.class));
+        when(appService.getApplicationExecutor()).thenReturn(executor);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testTimerChecksForNewHeapDumps() {
+
+        HeapInfo info1 = mock(HeapInfo.class);
+        HeapInfo info2 = mock(HeapInfo.class);
+        Collection<HeapInfo> infos = new ArrayList<HeapInfo>();
+        infos.add(info1);
+        infos.add(info2);
+
+        when(heapDao.getAllHeapInfo(any(VmRef.class))).thenReturn(infos);
+
+        createController();
+
+        timerActionCaptor.getValue().run();
+
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<List> heapDumps = ArgumentCaptor.forClass(List.class);
+        verify(view).updateHeapDumpList(heapDumps.capture());
+        assertTrue(heapDumps.getValue().contains(new HeapDump(info1, heapDao)));
+        assertTrue(heapDumps.getValue().contains(new HeapDump(info2, heapDao)));
+    }
+
+    @Test
+    public void testTimerFetchesMemoryDataAndUpdatesView() {
+        createController();
+        Runnable timerAction = timerActionCaptor.getValue();
+
+        final long CAPACITY = 10;
+        final long USED = 5;
+        Space space = new Space();
+        space.setCapacity(CAPACITY);
+        space.setMaxCapacity(20);
+        space.setUsed(USED);
+        Generation gen = new Generation();
+        gen.setName("foobar");
+        gen.setSpaces(new Space[] { space });
+        VmMemoryStat stat = new VmMemoryStat();
+        stat.setGenerations(new Generation[] { gen });
+
+        when(vmDao.getLatestVmMemoryStats(isA(VmRef.class), anyLong()))
+                .thenReturn(Arrays.asList(stat));
+
+        timerAction.run();
+
+        ArgumentCaptor<Long> timeStampCaptor = ArgumentCaptor
+                .forClass(Long.class);
+        verify(vmDao).getLatestVmMemoryStats(isA(VmRef.class),
+                timeStampCaptor.capture());
+        assertTimeStampIsAround(
+                System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1),
+                timeStampCaptor.getValue());
+        verify(view).updateUsedAndCapacity(USED + " B", CAPACITY + " B");
+    }
+
+    @Test
+    public void testTimerFetchesMemoryDataDeltaOnly() {
+        ArgumentCaptor<Long> timeStampCaptor = ArgumentCaptor
+                .forClass(Long.class);
+
+        final long DATA_TIMESTAMP = System.currentTimeMillis() + 1000000000;
+        Space space = new Space();
+        space.setCapacity(10);
+        space.setMaxCapacity(20);
+        space.setUsed(5);
+        Generation gen = new Generation();
+        gen.setName("foobar");
+        gen.setSpaces(new Space[] { space });
+        VmMemoryStat stat = new VmMemoryStat();
+        stat.setTimeStamp(DATA_TIMESTAMP);
+        stat.setGenerations(new Generation[] { gen });
+
+        when(vmDao.getLatestVmMemoryStats(isA(VmRef.class), anyLong()))
+                .thenReturn(Arrays.asList(stat));
+
+        createController();
+        Runnable timerAction = timerActionCaptor.getValue();
+
+        timerAction.run();
+        timerAction.run();
+
+        verify(vmDao, times(2)).getLatestVmMemoryStats(isA(VmRef.class),
+                timeStampCaptor.capture());
+
+        long timeStamp1 = timeStampCaptor.getAllValues().get(0);
+        assertTimeStampIsAround(
+                System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1),
+                timeStamp1);
+
+        long timeStamp2 = timeStampCaptor.getAllValues().get(1);
+        assertTimeStampIsAround(DATA_TIMESTAMP, timeStamp2);
+    }
+
+    @Test
+    public void testTimerFetchesMemoryDataDeltaOnlyEvenWithNoData() {
+        ArgumentCaptor<Long> timeStampCaptor = ArgumentCaptor
+                .forClass(Long.class);
+
+        createController();
+        Runnable timerAction = timerActionCaptor.getValue();
+
+        timerAction.run();
+        timerAction.run();
+
+        verify(vmDao, times(2)).getLatestVmMemoryStats(isA(VmRef.class),
+                timeStampCaptor.capture());
+
+        long timeStamp1 = timeStampCaptor.getAllValues().get(0);
+        assertTimeStampIsAround(
+                System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1),
+                timeStamp1);
+
+        long timeStamp2 = timeStampCaptor.getAllValues().get(1);
+        assertTimeStampIsAround(
+                System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1),
+                timeStamp2);
+    }
+
+    private void assertTimeStampIsAround(long expected, long actual) {
+        assertTrue(actual <= expected + 1000);
+        assertTrue(actual >= expected - 1000);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumpDetailsControllerTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,119 @@
+/*
+ * 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.vm.heap.analysis.client.core.internal;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.ApplicationService;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram;
+
+public class HeapDumpDetailsControllerTest {
+
+    private HeapDumpDetailsView view;
+    private HeapDumpDetailsViewProvider viewProvider;
+    private HeapHistogramViewProvider histogramProvider;
+    private ObjectDetailsViewProvider objectDetailsProvider;
+    private ObjectRootsViewProvider objectRootsProvider;
+
+    @Before
+    public void setUp() {
+        viewProvider = mock(HeapDumpDetailsViewProvider.class);
+        view = mock(HeapDumpDetailsView.class);
+        when(viewProvider.createView()).thenReturn(view);
+
+        HeapHistogramView histogramView = mock(HeapHistogramView.class);
+        histogramProvider = mock(HeapHistogramViewProvider.class);
+        when(histogramProvider.createView()).thenReturn(histogramView);
+
+        ObjectDetailsView objectView = mock(ObjectDetailsView.class);
+        objectDetailsProvider = mock(ObjectDetailsViewProvider.class);
+        when(objectDetailsProvider.createView()).thenReturn(objectView);
+
+        ObjectRootsView objectRootsView = mock(ObjectRootsView.class);
+        objectRootsProvider = mock(ObjectRootsViewProvider.class);
+        when(objectRootsProvider.createView()).thenReturn(objectRootsView);
+    }
+
+    @After
+    public void tearDown() {
+        viewProvider = null;
+        histogramProvider = null;
+        objectDetailsProvider = null;
+        objectRootsProvider = null;
+    }
+
+    @Test
+    public void verifyInitialize() throws IOException {
+        ApplicationService appService = mock(ApplicationService.class);
+
+        ObjectHistogram histogram = mock(ObjectHistogram.class);
+
+        HeapDump dump = mock(HeapDump.class);
+        when(dump.getHistogram()).thenReturn(histogram);
+
+        HeapDumpDetailsController controller = new HeapDumpDetailsController(
+                appService, viewProvider, histogramProvider,
+                objectDetailsProvider, objectRootsProvider);
+        controller.setDump(dump);
+
+        verify(dump).searchObjects(isA(String.class), anyInt());
+        verify(view)
+                .addSubView(isA(String.class), isA(HeapHistogramView.class));
+        verify(view)
+                .addSubView(isA(String.class), isA(ObjectDetailsView.class));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/HeapDumperTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,101 @@
+/*
+ * 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.vm.heap.analysis.client.core.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.common.cli.Arguments;
+import com.redhat.thermostat.common.cli.Command;
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandContextFactory;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.CommandRegistry;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.VmRef;
+
+public class HeapDumperTest {
+    private static final String TEST_HOST_ID = "1111111";
+    private static final int TEST_VM_ID = 2222222;
+
+    private Command command;
+    private HeapDumper dumper;
+    private CommandContextFactory ctxFactory;
+    private CommandRegistry reg;
+    
+    @Before
+    public void setUp() throws Exception {
+        command = mock(Command.class);
+        ctxFactory = mock(CommandContextFactory.class);
+        reg = mock(CommandRegistry.class);
+        CommandContext ctx = mock(CommandContext.class);
+        
+        when(reg.getCommand(any(String.class))).thenReturn(command);
+        when(ctxFactory.getCommandRegistry()).thenReturn(reg);
+        when(ctxFactory.createContext(any(Arguments.class))).thenReturn(ctx);
+        
+        HostRef hostRef = new HostRef(TEST_HOST_ID, "myHost");
+        VmRef ref = new VmRef(hostRef, TEST_VM_ID, "myVM");
+        dumper = new HeapDumper(ref, ctxFactory);
+    }
+
+    @Test
+    public void testCommand() {
+        verify(reg).getCommand(eq("dump-heap"));
+    }
+    
+    @Test
+    public void testDump() throws CommandException {
+        dumper.dump();
+        
+        ArgumentCaptor<Arguments> captor = ArgumentCaptor.forClass(Arguments.class);
+        verify(ctxFactory).createContext(captor.capture());
+        Arguments args = captor.getValue();
+        
+        assertEquals(TEST_HOST_ID, args.getArgument("hostId"));
+        assertEquals(String.valueOf(TEST_VM_ID), args.getArgument("vmId"));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/ObjectDetailsControllerTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,289 @@
+/*
+ * 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.vm.heap.analysis.client.core.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.contains;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.stubbing.OngoingStubbing;
+
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ApplicationService;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapObjectUI;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsView.ObjectAction;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+import com.sun.tools.hat.internal.model.JavaClass;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+
+public class ObjectDetailsControllerTest {
+
+    private ObjectDetailsView view;
+    private ApplicationService appService;
+    private ObjectRootsViewProvider objectRootsProvider;
+    private ObjectDetailsViewProvider objectDetailsProvider;
+
+    private ArgumentCaptor<Runnable> runnableCaptor;
+
+    @Before
+    public void setUp() {
+        view = mock(ObjectDetailsView.class);
+        objectDetailsProvider = mock(ObjectDetailsViewProvider.class);
+        when(objectDetailsProvider.createView()).thenReturn(view);
+        
+        objectRootsProvider = mock(ObjectRootsViewProvider.class);
+        when(objectRootsProvider.createView()).thenReturn(mock(ObjectRootsView.class));
+        runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+        ExecutorService executorService = mock(ExecutorService.class);
+        doNothing().when(executorService).execute(runnableCaptor.capture());
+
+        appService = mock(ApplicationService.class);
+        when(appService.getApplicationExecutor()).thenReturn(executorService);
+    }
+
+    @After
+    public void tearDown() {
+        view = null;
+        objectDetailsProvider = null;
+        objectRootsProvider = null;
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Test
+    public void verifySearchWorks() {
+        final String SEARCH_TEXT = "Test";
+        final String OBJECT_ID = "0xcafebabe";
+        final String OBJECT_CLASS_NAME = "FOO";
+
+        when(view.getSearchText()).thenReturn(SEARCH_TEXT);
+
+        JavaClass heapObjectClass = mock(JavaClass.class);
+        when(heapObjectClass.getName()).thenReturn(OBJECT_CLASS_NAME);
+
+        JavaHeapObject heapObject = mock(JavaHeapObject.class);
+        when(heapObject.getIdString()).thenReturn(OBJECT_ID);
+        when(heapObject.getClazz()).thenReturn(heapObjectClass);
+
+        HeapDump dump = mock(HeapDump.class);
+        when(dump.searchObjects(contains(SEARCH_TEXT), anyInt())).thenReturn(Arrays.asList(OBJECT_ID));
+        when(dump.findObject(eq(OBJECT_ID))).thenReturn(heapObject);
+
+        ArgumentCaptor<ActionListener> viewArgumentCaptor1 = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addObjectActionListener(viewArgumentCaptor1.capture());
+
+        @SuppressWarnings("unused")
+        ObjectDetailsController controller = new ObjectDetailsController(appService, dump, this.objectDetailsProvider, this.objectRootsProvider);
+
+        ActionListener<ObjectAction> actionListener = viewArgumentCaptor1.getValue();
+        assertNotNull(actionListener);
+        actionListener.actionPerformed(new ActionEvent<ObjectAction>(view, ObjectAction.SEARCH));
+
+        runnableCaptor.getValue().run();
+
+        ArgumentCaptor<Collection> matchingObjectsCaptor = ArgumentCaptor.forClass(Collection.class);
+        verify(view).setMatchingObjects(matchingObjectsCaptor.capture());
+
+        List<HeapObjectUI> matchingObjects = new ArrayList<HeapObjectUI>(matchingObjectsCaptor.getValue());
+        assertEquals(1, matchingObjects.size());
+        assertEquals(OBJECT_ID, matchingObjects.get(0).objectId);
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Test
+    public void verifyInputConvertedIntoWildcardsIfNeeded() {
+        HeapDump heap = mock(HeapDump.class);
+        when(view.getSearchText()).thenReturn("a");
+
+        ArgumentCaptor<ActionListener> objectActionListenerCaptor = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addObjectActionListener(objectActionListenerCaptor.capture());
+
+        @SuppressWarnings("unused")
+        ObjectDetailsController controller = new ObjectDetailsController(appService, heap, this.objectDetailsProvider, this.objectRootsProvider);
+
+        ActionListener<ObjectAction> actionListener = objectActionListenerCaptor.getValue();
+        assertNotNull(actionListener);
+        actionListener.actionPerformed(new ActionEvent<ObjectAction>(view, ObjectAction.SEARCH));
+
+        runnableCaptor.getValue().run();
+
+        verify(heap).searchObjects("*a*", 100);
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Test
+    public void verifyWildcardInputNotConvertedIntoWildcards() {
+        HeapDump heap = mock(HeapDump.class);
+        when(view.getSearchText()).thenReturn("*a?");
+
+        ArgumentCaptor<ActionListener> objectActionListenerCaptor = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addObjectActionListener(objectActionListenerCaptor.capture());
+
+        @SuppressWarnings("unused")
+        ObjectDetailsController controller = new ObjectDetailsController(appService, heap, this.objectDetailsProvider, this.objectRootsProvider);
+
+        ActionListener<ObjectAction> actionListener = objectActionListenerCaptor.getValue();
+        assertNotNull(actionListener);
+        actionListener.actionPerformed(new ActionEvent<ObjectAction>(view, ObjectAction.SEARCH));
+
+        runnableCaptor.getValue().run();
+
+        verify(heap).searchObjects("*a?", 300);
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Test
+    public void verifySearchLimits() {
+
+        Object[][] limits = new Object[][] {
+            { "a",       100 },
+            { "ab",      200 },
+            { "abc",     300 },
+            { "abcd",    400 },
+            { "abcde",   500 },
+            { "abcdef",  600},
+            { "abcdefg", 700},
+            { "java.lang.Class", 1000 },
+        };
+
+        HeapDump heap = mock(HeapDump.class);
+
+        OngoingStubbing<String> ongoing = when(view.getSearchText());
+        for (int i = 0; i < limits.length; i++) {
+            ongoing = ongoing.thenReturn((String)limits[i][0]);
+        }
+
+        ArgumentCaptor<ActionListener> objectActionListenerCaptor = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addObjectActionListener(objectActionListenerCaptor.capture());
+
+        @SuppressWarnings("unused")
+        ObjectDetailsController controller = new ObjectDetailsController(appService, heap, this.objectDetailsProvider, this.objectRootsProvider);
+
+        ActionListener<ObjectAction> actionListener = objectActionListenerCaptor.getValue();
+        assertNotNull(actionListener);
+
+        for (int i = 0; i < limits.length; i++) {
+            actionListener.actionPerformed(new ActionEvent<ObjectAction>(view, ObjectAction.SEARCH));
+            runnableCaptor.getValue().run();
+        }
+
+        InOrder inOrder = inOrder(heap);
+        for (int i = 0; i < limits.length; i++) {
+            String text = (String) limits[i][0];
+            int times = (Integer) limits[i][1];
+            inOrder.verify(heap).searchObjects("*" + text + "*", times);
+        }
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Test
+    public void verifyGettingDetailsWorks() {
+        final String OBJECT_ID = "0xcafebabe";
+        final String OBJECT_ID_VISIBLE = "FOO BAR";
+
+        JavaHeapObject heapObject = mock(JavaHeapObject.class);
+
+        HeapObjectUI heapObjectRepresentation = new HeapObjectUI(OBJECT_ID, OBJECT_ID_VISIBLE);
+
+        HeapDump dump = mock(HeapDump.class);
+        when(dump.findObject(OBJECT_ID)).thenReturn(heapObject);
+
+        ArgumentCaptor<ActionListener> viewArgumentCaptor1 = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addObjectActionListener(viewArgumentCaptor1.capture());
+
+        when(view.getSelectedMatchingObject()).thenReturn(heapObjectRepresentation);
+
+        @SuppressWarnings("unused")
+        ObjectDetailsController controller = new ObjectDetailsController(appService, dump, this.objectDetailsProvider, this.objectRootsProvider);
+
+        ActionListener<ObjectAction> actionListener = viewArgumentCaptor1.getValue();
+        assertNotNull(actionListener);
+        actionListener.actionPerformed(new ActionEvent<ObjectAction>(view, ObjectAction.GET_OBJECT_DETAIL));
+
+        verify(view).setObjectDetails(heapObject);
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Test
+    public void verifyFindRoot() {
+        final String OBJECT_ID = "0xcafebabe";
+        final String OBJECT_ID_VISIBLE = "FOO BAR";
+
+        JavaHeapObject heapObject = mock(JavaHeapObject.class);
+
+        HeapObjectUI heapObjectRepresentation = new HeapObjectUI(OBJECT_ID, OBJECT_ID_VISIBLE);
+
+        HeapDump dump = mock(HeapDump.class);
+        when(dump.findObject(OBJECT_ID)).thenReturn(heapObject);
+
+        ArgumentCaptor<ActionListener> viewArgumentCaptor1 = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addObjectActionListener(viewArgumentCaptor1.capture());
+
+        when(view.getSelectedMatchingObject()).thenReturn(heapObjectRepresentation);
+
+        @SuppressWarnings("unused")
+        ObjectDetailsController controller = new ObjectDetailsController(appService, dump, this.objectDetailsProvider, this.objectRootsProvider);
+
+        ActionListener<ObjectAction> actionListener = viewArgumentCaptor1.getValue();
+        assertNotNull(actionListener);
+        actionListener.actionPerformed(new ActionEvent<ObjectAction>(view, ObjectAction.GET_OBJECT_DETAIL));
+
+        verify(view).setObjectDetails(heapObject);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/core/internal/ObjectRootsControllerTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,153 @@
+/*
+ * 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.vm.heap.analysis.client.core.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapObjectUI;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsView.Action;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.command.FindRoot;
+import com.redhat.thermostat.vm.heap.analysis.command.HeapPath;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+import com.sun.tools.hat.internal.model.JavaClass;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+
+public class ObjectRootsControllerTest {
+
+    ObjectRootsController controller;
+
+    HeapDump heapDump;
+    JavaHeapObject heapObject;
+    JavaClass clazz;
+    FindRoot rootFinder;
+
+    ObjectRootsView view;
+    ActionListener<Action> listener;
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Before
+    public void setUp() {
+        // Set up views
+        view = mock(ObjectRootsView.class);
+
+        ObjectRootsViewProvider viewProvider = mock(ObjectRootsViewProvider.class);
+        when(viewProvider.createView()).thenReturn(view);
+        
+        // set up models
+        heapObject = mock(JavaHeapObject.class);
+        when(heapObject.getIdString()).thenReturn("id-string");
+
+        clazz = mock(JavaClass.class);
+        when(clazz.getName()).thenReturn("class");
+        when(heapObject.getClazz()).thenReturn(clazz);
+
+        heapDump = mock(HeapDump.class);
+        when(heapDump.findObject("test")).thenReturn(heapObject);
+
+        rootFinder = mock(FindRoot.class);
+
+        // create controller
+        controller = new ObjectRootsController(heapDump, heapObject, rootFinder, viewProvider);
+
+        ArgumentCaptor<ActionListener> listenerCaptor = ArgumentCaptor.forClass(ActionListener.class);
+        verify(view).addActionListener(listenerCaptor.capture());
+
+        listener = listenerCaptor.getValue();
+    }
+
+
+    @Test
+    public void verifyAddListenersToView() {
+        assertNotNull(listener);
+    }
+
+    @Test
+    public void verifySetObjectDetailsInView() {
+        when(heapObject.getIdString()).thenReturn("object-id");
+        when(heapObject.isHeapAllocated()).thenReturn(true);
+        when(heapObject.getSize()).thenReturn(10);
+
+        when(clazz.getName()).thenReturn("object-class");
+
+        HeapObjectUI heapObj = new HeapObjectUI("test", "test");
+        ActionEvent<Action> event = new ActionEvent<Action>(view, Action.OBJECT_SELECTED);
+        event.setPayload(heapObj);
+        listener.actionPerformed(event);
+
+        verify(view).setObjectDetails("Object ID: object-id\n" +
+                "Type: object-class\n" +
+                "Size: 10 bytes\n" +
+                "Heap allocated: true\n");
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Test
+    public void testShow() {
+
+        HeapPath<JavaHeapObject> path = mock(HeapPath.class);
+        when(path.iterator()).thenReturn(Arrays.asList(heapObject).iterator());
+
+        when(rootFinder.findShortestPathsToRoot(heapObject, false)).thenReturn(Arrays.asList(path));
+
+        controller.show();
+
+        ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
+
+        verify(view).setPathToRoot(captor.capture());
+
+        HeapObjectUI heapObj = (HeapObjectUI) captor.getValue().get(0);
+        assertEquals("id-string", heapObj.objectId);
+        assertEquals("class@id-string", heapObj.text);
+
+        verify(view).showView();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-core/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/locale/LocaleResourcesTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,54 @@
+/*
+ * 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.vm.heap.analysis.client.locale;
+
+import com.redhat.thermostat.test.locale.AbstractLocaleResourcesTest;
+
+public class LocaleResourcesTest extends AbstractLocaleResourcesTest<LocaleResources> {
+
+    @Override
+    protected Class<LocaleResources> getEnumClass() {
+        return LocaleResources.class;
+    }
+
+    @Override
+    protected String getResourceBundle() {
+        return LocaleResources.RESOURCE_BUNDLE;
+    }
+
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/pom.xml	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,148 @@
+<?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>
+    <artifactId>thermostat-vm-heap-analysis</artifactId>
+    <groupId>com.redhat.thermostat</groupId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>thermostat-vm-heap-analysis-client-swing</artifactId>
+  <packaging>bundle</packaging>
+  <name>Thermostat Heap Analysis Swing Client plugin</name>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-Activator>com.redhat.thermostat.vm.heap.analysis.client.swing.internal.Activator</Bundle-Activator>
+            <Bundle-SymbolicName>com.redhat.thermostat.vm.heap.analysis.client.swing</Bundle-SymbolicName>
+            <Private-Package>
+               com.redhat.thermostat.vm.heap.analysis.client.swing.internal
+            </Private-Package>
+            <!-- Do not autogenerate uses clauses in Manifests -->
+            <_nouses>true</_nouses>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.easytesting</groupId>
+      <artifactId>fest-swing</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>net.java.openjdk.cacio</groupId>
+      <artifactId>cacio-tta</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-client-swing</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-tools</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-vm-heap-analysis-common</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-vm-heap-analysis-client-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-vm-heap-analysis-agent</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.jfree</groupId>
+      <artifactId>jfreechart</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.sun</groupId>
+      <artifactId>tools</artifactId>
+      <scope>system</scope>
+      <systemPath>${java.home}/../lib/tools.jar</systemPath>
+    </dependency>
+    
+  </dependencies>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/Activator.java	Wed Dec 12 15:52:00 2012 -0500
@@ -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.vm.heap.analysis.client.swing.internal;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsViewProvider;
+
+public class Activator implements BundleActivator {
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        // All automatically unregistered upon Activator.stop
+        HeapViewProvider viewProvider = new SwingHeapViewProvider();
+        context.registerService(HeapViewProvider.class.getName(), viewProvider, null);
+        HeapDumpDetailsViewProvider detailsViewProvider = new SwingHeapDumpDetailsViewProvider();
+        context.registerService(HeapDumpDetailsViewProvider.class.getName(), detailsViewProvider, null);
+        HeapHistogramViewProvider histogramViewProvider = new SwingHeapHistogramViewProvider();
+        context.registerService(HeapHistogramViewProvider.class.getName(), histogramViewProvider, null);
+        ObjectDetailsViewProvider objectDetailsViewProvider = new SwingObjectDetailsViewProvider();
+        context.registerService(ObjectDetailsViewProvider.class.getName(), objectDetailsViewProvider, null);
+        ObjectRootsViewProvider objectRootsViewProvider = new SwingObjectRootsViewProvider();
+        context.registerService(ObjectRootsViewProvider.class.getName(), objectRootsViewProvider, null);
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapDetailsSwing.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,117 @@
+/*
+ * 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.vm.heap.analysis.client.swing.internal;
+
+import java.awt.BorderLayout;
+
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import javax.swing.SwingUtilities;
+
+import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsView;
+
+public class HeapDetailsSwing extends HeapDumpDetailsView implements SwingComponent {
+
+    /** For TESTING only! */
+    static final String TAB_NAME = "tabs";
+
+    private JPanel visiblePane;
+
+    private JTabbedPane tabPane = new JTabbedPane();
+
+    public HeapDetailsSwing() {
+        visiblePane = new JPanel();
+        visiblePane.setLayout(new BorderLayout());
+        visiblePane.add(tabPane, BorderLayout.CENTER);
+
+        tabPane.setName(TAB_NAME);
+    }
+
+    @Override
+    public void addSubView(final String title, final HeapHistogramView view) {
+        verifyIsSwingComponent(view);
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                tabPane.insertTab(title, null, ((SwingComponent)view).getUiComponent(), null, 0);
+            }
+        });
+    }
+
+    @Override
+    public void addSubView(final String title, final ObjectDetailsView view) {
+        verifyIsSwingComponent(view);
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                tabPane.insertTab(title, null, ((SwingComponent)view).getUiComponent(), null, 1);
+            }
+        });
+    }
+
+    @Override
+    public void removeSubView(final String title) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                int tabCount = tabPane.getTabCount();
+                for (int i = 0; i < tabCount; i++) {
+                    String tabTitle = tabPane.getTitleAt(i);
+                    if (tabTitle.equals(title)) {
+                        tabPane.removeTabAt(i);
+                        return;
+                    }
+                }
+            }
+        });
+    }
+
+    @Override
+    public JPanel getUiComponent() {
+        return visiblePane;
+    }
+
+    private void verifyIsSwingComponent(Object obj) {
+        if (!(obj instanceof SwingComponent)) {
+            throw new IllegalArgumentException("component is not swing");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapPanel.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,92 @@
+/*
+ * 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.vm.heap.analysis.client.swing.internal;
+
+import java.awt.Dimension;
+
+import javax.swing.JPanel;
+import javax.swing.JSplitPane;
+import javax.swing.GroupLayout;
+import javax.swing.GroupLayout.Alignment;
+
+@SuppressWarnings("serial")
+public class HeapPanel extends JPanel {
+
+    private JSplitPane splitPane;
+    
+    public HeapPanel() {
+        
+        splitPane = new JSplitPane();
+        splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
+        GroupLayout groupLayout = new GroupLayout(this);
+        groupLayout.setHorizontalGroup(
+            groupLayout.createParallelGroup(Alignment.LEADING)
+                .addComponent(splitPane, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 450, Short.MAX_VALUE)
+        );
+        groupLayout.setVerticalGroup(
+            groupLayout.createParallelGroup(Alignment.LEADING)
+                .addGroup(groupLayout.createSequentialGroup()
+                    .addGap(5)
+                    .addComponent(splitPane, GroupLayout.DEFAULT_SIZE, 295, Short.MAX_VALUE))
+        );
+
+        splitPane.setOneTouchExpandable(true);
+        setLayout(groupLayout);
+    }
+
+    void divideView() {
+        splitPane.setDividerLocation(.5d);
+    }
+    
+    void hideBottom() {
+        splitPane.getBottomComponent().setMinimumSize(new Dimension(0, 0));
+        splitPane.setDividerLocation(1.0d);
+    }
+    
+    void hideTop() {
+        splitPane.getTopComponent().setMinimumSize(new Dimension(0, 0));
+        splitPane.setDividerLocation(0.0d);
+    }
+    
+    void setTop(JPanel panel) {
+        splitPane.setTopComponent(panel);
+    }
+    
+    void setBottom(JPanel panel) {
+        splitPane.setBottomComponent(panel);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapSwingView.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,236 @@
+/*
+ * 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.vm.heap.analysis.client.swing.internal;
+
+import java.awt.Component;
+import java.awt.EventQueue;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.List;
+
+import javax.swing.BoxLayout;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import org.jfree.chart.ChartPanel;
+
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.client.swing.components.HeaderPanel;
+import com.redhat.thermostat.client.ui.ComponentVisibleListener;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.chart.OverviewChart;
+import com.redhat.thermostat.vm.heap.analysis.client.locale.LocaleResources;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+
+public class HeapSwingView extends HeapView implements SwingComponent {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private StatsPanel stats;
+
+    private HeapPanel heapDetailPanel;
+    private HeaderPanel overview;
+    
+    private JPanel visiblePane;
+    
+    public HeapSwingView() {
+        stats = new StatsPanel();
+        stats.addHeapDumperListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                
+                stats.disableHeapDumperControl();
+                
+                heapDumperNotifier.fireAction(HeapDumperAction.DUMP_REQUESTED);
+            }
+        });
+        
+        stats.addDumpListListener(new ListSelectionListener() {
+            @Override
+            public void valueChanged(ListSelectionEvent arg0) {
+                HeapDump dump = stats.getSelectedHeapDump();
+                heapDumperNotifier.fireAction(HeapDumperAction.ANALYSE, dump);
+            }
+        });
+        
+        visiblePane = new JPanel();
+        visiblePane.setLayout(new BoxLayout(visiblePane, BoxLayout.X_AXIS));
+        
+        heapDetailPanel = new HeapPanel();
+        
+        overview = new HeaderPanel(translator.localize(LocaleResources.HEAP_OVERVIEW_TITLE));
+        overview.setContent(stats);
+        overview.addHierarchyListener(new ViewVisibleListener());
+
+        // at the beginning, only the overview is visible
+        visiblePane.add(overview);
+    }
+    
+    private class ViewVisibleListener extends ComponentVisibleListener {
+        @Override
+        public void componentShown(Component component) {
+            HeapSwingView.this.notify(Action.VISIBLE);
+        }
+
+        @Override
+        public void componentHidden(Component component) {
+            HeapSwingView.this.notify(Action.HIDDEN);
+        }
+    }
+
+    @Override
+    public void setModel(final OverviewChart model) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                ChartPanel charts = new ChartPanel(model.createChart(stats.getWidth(), stats.getBackground()));
+                /*
+                 * By default, ChartPanel scales itself instead of redrawing things when
+                 * it's resized. To have it resize automatically, we need to set minimum
+                 * and maximum sizes. Lets constrain the minimum, but not the maximum
+                 * size.
+                 */
+                final int MINIMUM_DRAW_SIZE = 100;
+
+                charts.setMinimumDrawHeight(MINIMUM_DRAW_SIZE);
+                charts.setMinimumDrawWidth(MINIMUM_DRAW_SIZE);
+
+                charts.setMaximumDrawHeight(Integer.MAX_VALUE);
+                charts.setMaximumDrawWidth(Integer.MAX_VALUE);
+
+                stats.setChartPanel(charts);
+            }
+        });
+    }
+
+    @Override
+    public void updateUsedAndCapacity(final String used, final String capacity) {
+        
+        SwingUtilities.invokeLater(new Runnable() {
+            
+            @Override
+            public void run() {
+                stats.setMax(capacity);
+                stats.setUsed(used);
+            }
+        });
+    }
+
+    @Override
+    public void addHeapDump(final HeapDump dump) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                stats.addDump(dump);
+            }
+        });
+    }
+    
+    @Override
+    public void clearHeapDumpList() {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                stats.clearDumpList();
+            }
+        });
+    }
+    
+    @Override
+    public void openDumpView() {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                visiblePane.removeAll();
+                heapDetailPanel.divideView();
+                heapDetailPanel.setTop(overview);
+
+                visiblePane.add(heapDetailPanel);
+                visiblePane.revalidate();
+            }
+        });
+    }
+
+    @Override
+    public void setChildView(BasicView childView) {
+        if (childView instanceof HeapDetailsSwing) {
+            final HeapDetailsSwing view = (HeapDetailsSwing)childView;
+            SwingUtilities.invokeLater(new Runnable() {
+                @Override
+                public void run() {
+                    heapDetailPanel.setBottom(view.getUiComponent());
+                    visiblePane.revalidate();
+                }
+            });
+        }
+    }
+    
+    @Override
+    public Component getUiComponent() {
+        return visiblePane;
+    }
+
+    @Override
+    public void notifyHeapDumpComplete() {
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                stats.enableHeapDumperControl();
+            }
+        });
+    }
+
+    @Override
+    public void updateHeapDumpList(final List<HeapDump> heapDumps) {
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                stats.updateHeapDumpList(heapDumps);
+            }
+        });
+    }
+
+    @Override
+    public void displayWarning(String string) {
+        JOptionPane.showMessageDialog(visiblePane, string, "Warning", JOptionPane.WARNING_MESSAGE);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HistogramPanel.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,176 @@
+/*
+ * 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.vm.heap.analysis.client.swing.internal;
+
+import java.awt.Component;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.BoxLayout;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.table.DefaultTableModel;
+
+import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.client.swing.components.HeaderPanel;
+import com.redhat.thermostat.client.swing.components.ThermostatTable;
+import com.redhat.thermostat.client.swing.components.ThermostatTableRenderer;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.DescriptorConverter;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramView;
+import com.redhat.thermostat.vm.heap.analysis.client.locale.LocaleResources;
+import com.redhat.thermostat.vm.heap.analysis.common.HistogramRecord;
+import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram;
+
+@SuppressWarnings("serial")
+public class HistogramPanel extends HeapHistogramView implements SwingComponent {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private final JPanel panel;
+
+    private HeaderPanel headerPanel;
+
+    public HistogramPanel() {
+        panel = new JPanel();
+        panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
+
+        headerPanel = new HeaderPanel(translator.localize(LocaleResources.HEAP_DUMP_CLASS_USAGE));
+        panel.add(headerPanel);
+    }
+
+    @Override
+    public void display(ObjectHistogram histogram) {
+        ThermostatTable table = new ThermostatTable(new HistogramTableModel(histogram));
+        table.setDefaultRenderer(Long.class, new NiceNumberFormatter());
+        headerPanel.setContent(table.wrap());
+    }
+
+    private final class NiceNumberFormatter extends ThermostatTableRenderer {
+
+        private final DecimalFormat formatter = new DecimalFormat("###,###.###");
+
+        private NiceNumberFormatter() {
+            setHorizontalAlignment(JLabel.RIGHT);
+        }
+
+        @Override
+        protected void setValue(Object v) {
+            String formatted = formatter.format(v);
+            setText(formatted);
+        }
+    }
+
+    private class HistogramTableModel extends DefaultTableModel {
+
+        private final String[] columnNames = new String[] {
+            translator.localize(LocaleResources.HEAP_DUMP_HISTOGRAM_COLUMN_CLASS),
+            translator.localize(LocaleResources.HEAP_DUMP_HISTOGRAM_COLUMN_INSTANCES),
+            translator.localize(LocaleResources.HEAP_DUMP_HISTOGRAM_COLUMN_SIZE),
+        };
+
+        private List<HistogramRecord> histogram;
+
+        public HistogramTableModel(ObjectHistogram objHistogram) {
+            histogram = new ArrayList<>();
+            histogram.addAll(objHistogram.getHistogram());
+        }
+
+        @Override
+        public String getColumnName(int column) {
+            return columnNames[column];
+        }
+
+        @Override
+        public Class<?> getColumnClass(int column) {
+            if (column == 0) {
+                return String.class;
+            } else {
+                return Long.class;
+            }
+        }
+
+        @Override
+        public Object getValueAt(int row, int column) {
+            Object result = null;
+            if (row >= histogram.size()) {
+                throw new ArrayIndexOutOfBoundsException();
+            }
+            if (histogram != null) {
+                HistogramRecord record = histogram.get(row);
+                switch (column) {
+                case 0:
+                    result = DescriptorConverter.toJavaType(record.getClassname());
+                    break;
+                case 1:
+                    result = Long.valueOf(record.getNumberOf());
+                    break;
+                case 2:
+                    result = Long.valueOf(record.getTotalSize());
+                    break;
+                default:
+                    throw new ArrayIndexOutOfBoundsException();
+                }
+            }
+            return result;
+        }
+
+        @Override
+        public int getColumnCount() {
+            return 3;
+        }
+
+        @Override
+        public int getRowCount() {
+            if (histogram != null) {
+                return histogram.size();
+            }
+            return 0;
+        }
+
+        @Override
+        public boolean isCellEditable(int row, int column) {
+            return false;
+        }
+    }
+
+    @Override
+    public Component getUiComponent() {
+        return panel;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/LazyMutableTreeNode.java	Wed Dec 12 15:52:00 2012 -0500
@@ -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.vm.heap.analysis.client.swing.internal;
+
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapObjectUI;
+
+@SuppressWarnings("serial")
+class LazyMutableTreeNode extends javax.swing.tree.DefaultMutableTreeNode {
+
+    public LazyMutableTreeNode() {
+        super();
+    }
+
+    public LazyMutableTreeNode(HeapObjectUI heapObjectUI) {
+        super(heapObjectUI);
+    }
+
+    @Override
+    public boolean isLeaf() {
+        return !getAllowsChildren();
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectDetailsPanel.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,437 @@
+/*
+ * 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.vm.heap.analysis.client.swing.internal;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.GroupLayout;
+import javax.swing.JPopupMenu;
+import javax.swing.JToggleButton;
+import javax.swing.JTree;
+import javax.swing.SwingUtilities;
+import javax.swing.GroupLayout.Alignment;
+import javax.swing.JLabel;
+
+import com.redhat.thermostat.client.core.views.SearchFieldView.SearchAction;
+import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.client.swing.components.EdtHelper;
+import com.redhat.thermostat.client.swing.views.SearchFieldSwingView;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionNotifier;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapObjectUI;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsView;
+import com.redhat.thermostat.vm.heap.analysis.client.locale.LocaleResources;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+
+import javax.swing.LayoutStyle.ComponentPlacement;
+import javax.swing.JScrollPane;
+import javax.swing.JTextPane;
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import javax.swing.JSplitPane;
+import javax.swing.event.TreeExpansionEvent;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.event.TreeWillExpandListener;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.ExpandVetoException;
+import javax.swing.tree.MutableTreeNode;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+
+/**
+ * A Panel that displays JavaHeapObjects and referrers and references.
+ */
+public class ObjectDetailsPanel extends ObjectDetailsView implements SwingComponent {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    /** For TESTING ONLY! */
+    static final String TREE_NAME = "ref-tree";
+    /** For TESTING ONLY! */
+    static final String DETAILS_NAME = "object-details";
+
+    private final ActionNotifier<ObjectAction> notifier = new ActionNotifier<>(this);
+
+    private final JPanel panel;
+
+    private final SearchFieldSwingView searchField;
+
+    private final LazyMutableTreeNode ROOT = new LazyMutableTreeNode(null);
+    /** all the nodes in this model must be {@link LazyMutableTreeNode}s */
+    private final DefaultTreeModel model = new DefaultTreeModel(ROOT);
+    private final JTree objectTree = new JTree(model);
+
+    private final JTextPane objectDetailsPane;
+
+    private final ButtonGroup refGroup = new ButtonGroup();
+    private final JToggleButton toggleReferrersButton;
+    private final JToggleButton toggleReferencesButton;
+
+    private final List<ObjectReferenceCallback> callbacks = new CopyOnWriteArrayList<>();
+
+    public ObjectDetailsPanel() {
+
+        panel = new JPanel();
+
+        JLabel searchLabel = new JLabel(translator.localize(LocaleResources.HEAP_DUMP_OBJECT_BROWSE_SEARCH_LABEL));
+
+        searchField = new SearchFieldSwingView();
+        searchField.setTooltip(translator.localize(LocaleResources.HEAP_DUMP_OBJECT_BROWSE_SEARCH_PATTERN_HELP));
+
+        JSplitPane splitPane = new JSplitPane();
+        splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
+        splitPane.setDividerLocation(0.8 /* 80% */);
+
+        toggleReferrersButton = new JToggleButton(translator.localize(LocaleResources.HEAP_DUMP_OBJECT_BROWSE_REFERRERS));
+        refGroup.add(toggleReferrersButton);
+
+        toggleReferencesButton = new JToggleButton(translator.localize(LocaleResources.HEAP_DUMP_OBJECT_BROWSE_REFERENCES));
+        refGroup.add(toggleReferencesButton);
+
+        toggleReferrersButton.setSelected(true);
+
+        GroupLayout groupLayout = new GroupLayout(panel);
+        groupLayout.setHorizontalGroup(
+            groupLayout.createParallelGroup(Alignment.LEADING)
+                .addGroup(groupLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
+                        .addGroup(groupLayout.createSequentialGroup()
+                            .addComponent(searchLabel)
+                            .addPreferredGap(ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                            .addComponent(toggleReferencesButton)
+                            .addPreferredGap(ComponentPlacement.RELATED)
+                            .addComponent(toggleReferrersButton))
+                        .addGroup(groupLayout.createSequentialGroup()
+                            .addGap(12)
+                            .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
+                                .addComponent(splitPane, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 447, Short.MAX_VALUE)
+                                .addComponent(searchField, GroupLayout.DEFAULT_SIZE, 447, Short.MAX_VALUE))))
+                    .addContainerGap())
+        );
+        groupLayout.setVerticalGroup(
+            groupLayout.createParallelGroup(Alignment.LEADING)
+                .addGroup(groupLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
+                        .addComponent(searchLabel)
+                        .addComponent(toggleReferrersButton)
+                        .addComponent(toggleReferencesButton))
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addComponent(searchField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addComponent(splitPane, GroupLayout.DEFAULT_SIZE, 314, Short.MAX_VALUE)
+                    .addContainerGap())
+        );
+
+        searchField.addActionListener(new ActionListener<SearchAction>() {
+            @Override
+            public void actionPerformed(ActionEvent<SearchAction> actionEvent) {
+                switch (actionEvent.getActionId()) {
+                case TEXT_CHANGED:
+                    notifier.fireAction(ObjectAction.SEARCH);
+                    break;
+                default:
+                    break;
+                }
+            }
+        });
+        searchField.setLabel(translator.localize(LocaleResources.HEAP_DUMP_OBJECT_BROWSE_SEARCH_HINT));
+
+        java.awt.event.ActionListener treeToggleListener = new java.awt.event.ActionListener() {
+            @Override
+            public void actionPerformed(java.awt.event.ActionEvent e) {
+                notifier.fireAction(ObjectAction.SEARCH);
+            }
+        };
+
+        JToggleButton[] buttons = getTreeModeButtons();
+        for (JToggleButton button: buttons) {
+            button.addActionListener(treeToggleListener);
+        }
+
+        JScrollPane scrollPane = new JScrollPane();
+        scrollPane.setViewportView(objectTree);
+
+        splitPane.setLeftComponent(scrollPane);
+
+        JPanel panel = new JPanel();
+        splitPane.setRightComponent(panel);
+
+        panel.setLayout(new BorderLayout(0, 0));
+
+        objectDetailsPane = new JTextPane();
+        objectDetailsPane.setName(DETAILS_NAME);
+        objectDetailsPane.setEditable(false);
+        panel.add(objectDetailsPane);
+        this.panel.setLayout(groupLayout);
+
+        initializeTree();
+        clearTree();
+    }
+
+    private void initializeTree() {
+        objectTree.setName(TREE_NAME);
+        objectTree.setRootVisible(false);
+        objectTree.setShowsRootHandles(true);
+        objectTree.setEditable(false);
+
+        objectTree.addTreeSelectionListener(new TreeSelectionListener() {
+            @Override
+            public void valueChanged(TreeSelectionEvent e) {
+                notifier.fireAction(ObjectAction.GET_OBJECT_DETAIL);
+            }
+        });
+
+        if (objectTree.getCellRenderer() instanceof DefaultTreeCellRenderer) {
+            DefaultTreeCellRenderer cellRenderer = (DefaultTreeCellRenderer) objectTree.getCellRenderer();
+            cellRenderer.setClosedIcon(null);
+            cellRenderer.setOpenIcon(null);
+            cellRenderer.setLeafIcon(null);
+        }
+
+        objectTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+        objectTree.expandPath(new TreePath(ROOT.getPath()));
+
+        objectTree.addTreeWillExpandListener(new TreeWillExpandListener() {
+
+            @Override
+            public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
+                if (new TreePath(ROOT.getPath()).equals(event.getPath())) {
+                    return;
+                }
+
+                lazyLoadChildren(event.getPath());
+            }
+
+            @Override
+            public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
+                if (new TreePath(ROOT.getPath()).equals(event.getPath())) {
+                    throw new ExpandVetoException(event, "root cant be collapsed");
+                }
+            }
+        });
+
+        objectTree.addMouseListener(new MouseAdapter() {
+            @Override
+            public void mousePressed(MouseEvent e) {
+                if (e.isPopupTrigger()) {
+                    int row = objectTree.getRowForLocation(e.getX(), e.getY());
+                    if (row == -1) {
+                        return;
+                    }
+
+                    TreePath path = objectTree.getPathForRow(row);
+                    final HeapObjectUI heapObject = (HeapObjectUI) ((LazyMutableTreeNode)path.getLastPathComponent()).getUserObject();
+                    JPopupMenu popup = new JPopupMenu();
+                    JMenuItem findRootItem = new JMenuItem(translator.localize(LocaleResources.HEAP_DUMP_OBJECT_FIND_ROOT));
+                    findRootItem.addActionListener(new java.awt.event.ActionListener() {
+                        @Override
+                        public void actionPerformed(java.awt.event.ActionEvent e) {
+                            notifier.fireAction(ObjectAction.SHOW_ROOT_TO_GC, heapObject);
+                        }
+                    });
+                    popup.add(findRootItem);
+                    popup.show(e.getComponent(), e.getX(), e.getY());
+                }
+            }
+        });
+    }
+
+    private void clearTree() {
+        // clear children from model
+        int childrenCount = ROOT.getChildCount();
+        for (int i = 0; i < childrenCount; i++) {
+            MutableTreeNode child = (MutableTreeNode) ROOT.getChildAt(0);
+            model.removeNodeFromParent(child);
+        }
+    }
+
+    private void lazyLoadChildren(TreePath path) {
+        LazyMutableTreeNode node = (LazyMutableTreeNode) path.getLastPathComponent();
+        if (node.getChildCount() > 0) {
+            // already processed
+            return;
+        }
+
+        if (toggleReferencesButton.isSelected()) {
+            addReferences(node);
+        } else if (toggleReferrersButton.isSelected()) {
+            addReferrers(node);
+        }
+    }
+
+    private void addReferrers(LazyMutableTreeNode node) {
+        HeapObjectUI data = (HeapObjectUI) node.getUserObject();
+
+        List<HeapObjectUI> referrers = new ArrayList<>();
+        for (ObjectReferenceCallback callback : callbacks) {
+            referrers.addAll(callback.getReferrers(data));
+        }
+
+        for (HeapObjectUI obj: referrers) {
+            model.insertNodeInto(new LazyMutableTreeNode(obj), node, node.getChildCount());
+        }
+    }
+
+    private void addReferences(LazyMutableTreeNode node) {
+        HeapObjectUI data = (HeapObjectUI) node.getUserObject();
+
+        List<HeapObjectUI> referrers = new ArrayList<>();
+        for (ObjectReferenceCallback callback : callbacks) {
+            referrers.addAll(callback.getReferences(data));
+        }
+
+        for (HeapObjectUI obj: referrers) {
+            model.insertNodeInto(new LazyMutableTreeNode(obj), node, node.getChildCount());
+        }
+    }
+
+    private JToggleButton[] getTreeModeButtons() {
+        return new JToggleButton[] { toggleReferencesButton, toggleReferrersButton };
+    }
+
+    @Override
+    public void addObjectActionListener(ActionListener<ObjectAction> listener) {
+        notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeObjectActionListnener(ActionListener<ObjectAction> listener) {
+        notifier.removeActionListener(listener);
+    }
+
+    @Override
+    public void addObjectReferenceCallback(ObjectReferenceCallback callback) {
+        callbacks.add(callback);
+    }
+
+    @Override
+    public void removeObjectReferenceCallback(ObjectReferenceCallback callback) {
+        callbacks.remove(callback);
+    }
+
+    @Override
+    public String getSearchText() {
+        try {
+            return new EdtHelper().callAndWait(new Callable<String>() {
+                @Override
+                public String call() throws Exception {
+                    return searchField.getSearchText();
+                }
+            });
+        } catch (InvocationTargetException | InterruptedException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    @Override
+    public void setMatchingObjects(final Collection<HeapObjectUI> objects) {
+        try {
+            new EdtHelper().callAndWait(new Runnable() {
+                @Override
+                public void run() {
+                    // clear children
+                    clearTree();
+
+                    // add new children
+                    for (HeapObjectUI object: objects) {
+                        MutableTreeNode node = new LazyMutableTreeNode(object);
+                        model.insertNodeInto(node, ROOT, ROOT.getChildCount());
+                    }
+                    objectTree.expandPath(new TreePath(ROOT.getPath()));
+                }
+            });
+        } catch (InvocationTargetException | InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void setObjectDetails(final JavaHeapObject obj) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                // TODO use some other gui control for this rather than a plain text box
+                String text = translator.localize(LocaleResources.COMMAND_OBJECT_INFO_OBJECT_ID) + obj.getIdString() + "\n" +
+                              translator.localize(LocaleResources.COMMAND_OBJECT_INFO_TYPE) + obj.getClazz().getName() + "\n" +
+                              translator.localize(LocaleResources.COMMAND_OBJECT_INFO_SIZE) + String.valueOf(obj.getSize()) + " bytes" + "\n" +
+                              translator.localize(LocaleResources.COMMAND_OBJECT_INFO_HEAP_ALLOCATED) + String.valueOf(obj.isHeapAllocated()) + "\n";
+                objectDetailsPane.setText(text);
+            }
+        });
+    }
+
+    /**
+     * @return null if no selected object
+     */
+    @Override
+    public HeapObjectUI getSelectedMatchingObject() {
+        try {
+            return new EdtHelper().callAndWait(new Callable<HeapObjectUI>() {
+                @Override
+                public HeapObjectUI call() throws Exception {
+                    LazyMutableTreeNode node = (LazyMutableTreeNode) objectTree.getSelectionPath().getLastPathComponent();
+                    return (HeapObjectUI) node.getUserObject();
+                }
+            });
+        } catch (InvocationTargetException | InterruptedException e) {
+            return null;
+        }
+    }
+
+    @Override
+    public Component getUiComponent() {
+        return panel;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectRootsFrame.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,241 @@
+/*
+ * 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.vm.heap.analysis.client.swing.internal;
+
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import javax.swing.GroupLayout;
+import javax.swing.GroupLayout.Alignment;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextPane;
+import javax.swing.JTree;
+import javax.swing.LayoutStyle.ComponentPlacement;
+import javax.swing.SwingUtilities;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.MutableTreeNode;
+import javax.swing.tree.TreePath;
+
+import com.redhat.thermostat.client.swing.components.EdtHelper;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ActionNotifier;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapObjectUI;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsView;
+import com.redhat.thermostat.vm.heap.analysis.client.locale.LocaleResources;
+
+@SuppressWarnings("serial")
+public class ObjectRootsFrame extends JFrame implements ObjectRootsView {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    /** For TESTING ONLY! */
+    static final String TREE_NAME = "roots-tree";
+
+    static final String DETAILS_NAME = "object-details";
+
+    private final ActionNotifier<Action> notifier = new ActionNotifier<>(this);
+
+    private final LazyMutableTreeNode ROOT = new LazyMutableTreeNode();
+    private final DefaultTreeModel dataModel;
+    private final JTree pathToRootTree;
+
+    private final JTextPane objectDetails;
+
+    public ObjectRootsFrame() {
+        setTitle(translator.localize(LocaleResources.OBJECT_ROOTS_VIEW_TITLE));
+
+        dataModel = new DefaultTreeModel(ROOT);
+        pathToRootTree = new JTree(dataModel);
+        pathToRootTree.setName(TREE_NAME);
+
+        JLabel lblNewLabel = new JLabel(translator.localize(LocaleResources.OBJECT_ROOTS_VIEW_TITLE));
+
+        JScrollPane scrollPane = new JScrollPane(pathToRootTree);
+
+        objectDetails = new JTextPane();
+        objectDetails.setName(DETAILS_NAME);
+
+        GroupLayout groupLayout = new GroupLayout(getContentPane());
+        groupLayout.setHorizontalGroup(
+            groupLayout.createParallelGroup(Alignment.TRAILING)
+                .addGroup(groupLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
+                        .addComponent(scrollPane, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 416, Short.MAX_VALUE)
+                        .addComponent(objectDetails, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 416, Short.MAX_VALUE)
+                        .addComponent(lblNewLabel, Alignment.LEADING))
+                    .addContainerGap())
+        );
+        groupLayout.setVerticalGroup(
+            groupLayout.createParallelGroup(Alignment.LEADING)
+                .addGroup(groupLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addComponent(lblNewLabel)
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 126, Short.MAX_VALUE)
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addComponent(objectDetails, GroupLayout.PREFERRED_SIZE, 93, GroupLayout.PREFERRED_SIZE)
+                    .addContainerGap())
+        );
+        getContentPane().setLayout(groupLayout);
+
+        addWindowListener(new WindowAdapter() {
+            @Override
+            public void windowOpened(WindowEvent e) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+
+            @Override
+            public void windowClosing(WindowEvent e) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
+
+        pathToRootTree.addTreeSelectionListener(new TreeSelectionListener() {
+            @Override
+            public void valueChanged(TreeSelectionEvent e) {
+                HeapObjectUI obj = (HeapObjectUI) ((LazyMutableTreeNode)e.getPath().getLastPathComponent()).getUserObject();
+                notifier.fireAction(Action.OBJECT_SELECTED, obj);
+            }
+        });
+
+
+    }
+
+    @Override
+    public void addActionListener(ActionListener<Action> listener) {
+        notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeActionListener(ActionListener<Action> listener) {
+        notifier.removeActionListener(listener);
+    }
+
+    @Override
+    public void showView() {
+        Callable<Boolean> hideViewRunnable = new Callable<Boolean>() {
+            @Override
+            public Boolean call() {
+                pack();
+                setVisible(true);
+                return new Boolean(true);
+            }
+        };
+        try {
+            new EdtHelper().callAndWait(hideViewRunnable);
+        } catch (InvocationTargetException | InterruptedException e) {
+            InternalError error = new InternalError();
+            error.initCause(e);
+            throw error;
+        }
+    }
+
+    @Override
+    public void hideView() {
+        Callable<Boolean> hideViewRunnable = new Callable<Boolean>() {
+            @Override
+            public Boolean call() {
+                setVisible(false);
+                dispose();
+                return new Boolean(true);
+            }
+        };
+        try {
+            new EdtHelper().callAndWait(hideViewRunnable);
+        } catch (InvocationTargetException | InterruptedException e) {
+            InternalError error = new InternalError();
+            error.initCause(e);
+            throw error;
+        }
+    }
+
+    @Override
+    public void setPathToRoot(List<HeapObjectUI> pathToRoot) {
+        final List<HeapObjectUI> path = new ArrayList<>(pathToRoot);
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                clearTree();
+
+                LazyMutableTreeNode node = ROOT;
+                node.setUserObject(path.get(0));
+                TreePath treePath = new TreePath(node);
+                LazyMutableTreeNode parent = ROOT;
+                for (int i = 1; i < path.size(); i++) {
+                    HeapObjectUI obj = path.get(i);
+                    node = new LazyMutableTreeNode(obj);
+                    dataModel.insertNodeInto(node, parent, node.getChildCount());
+                    parent = node;
+                    treePath = treePath.pathByAddingChild(node);
+                }
+
+                pathToRootTree.expandPath(treePath);
+                pathToRootTree.setSelectionPath(treePath);
+            }
+        });
+    }
+
+    private void clearTree() {
+        // clear children from model
+        int childrenCount = ROOT.getChildCount();
+        for (int i = 0; i < childrenCount; i++) {
+            MutableTreeNode child = (MutableTreeNode) ROOT.getChildAt(0);
+            dataModel.removeNodeFromParent(child);
+        }
+    }
+
+    @Override
+    public void setObjectDetails(final String information) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                objectDetails.setText(information);
+            }
+        });
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/StatsPanel.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,210 @@
+/*
+ * 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.vm.heap.analysis.client.swing.internal;
+
+import java.awt.event.ActionListener;
+import java.util.List;
+
+import javax.swing.BoxLayout;
+import javax.swing.DefaultListModel;
+import javax.swing.GroupLayout;
+import javax.swing.GroupLayout.Alignment;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.LayoutStyle.ComponentPlacement;
+import javax.swing.ListSelectionModel;
+import javax.swing.SwingConstants;
+import javax.swing.event.ListSelectionListener;
+
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+
+@SuppressWarnings("serial")
+public class StatsPanel extends JPanel {
+    
+    private JPanel leftPanel;
+    
+    private JButton heapDumpButton;
+    private JList<HeapDump> dumpList;
+    private DefaultListModel<HeapDump> listModel;
+    
+    private JLabel max;
+    private JLabel current;
+    
+    public StatsPanel() {
+        
+        leftPanel = new JPanel();
+        leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.X_AXIS));
+        
+        JPanel rightPanel = new JPanel();
+        GroupLayout groupLayout = new GroupLayout(this);
+        groupLayout.setHorizontalGroup(
+            groupLayout.createParallelGroup(Alignment.LEADING)
+                .addGroup(Alignment.TRAILING, groupLayout.createSequentialGroup()
+                    .addComponent(leftPanel, GroupLayout.DEFAULT_SIZE, 343, Short.MAX_VALUE)
+                    .addPreferredGap(ComponentPlacement.UNRELATED)
+                    .addComponent(rightPanel, GroupLayout.PREFERRED_SIZE, 252, GroupLayout.PREFERRED_SIZE))
+        );
+        groupLayout.setVerticalGroup(
+            groupLayout.createParallelGroup(Alignment.LEADING)
+                .addComponent(rightPanel, GroupLayout.DEFAULT_SIZE, 293, Short.MAX_VALUE)
+                .addComponent(leftPanel, GroupLayout.DEFAULT_SIZE, 293, Short.MAX_VALUE)
+        );
+        
+        JLabel currentLabel = new JLabel("used:");
+        currentLabel.setHorizontalAlignment(SwingConstants.LEFT);
+        
+        JLabel maxLabel = new JLabel("capacity:");
+        maxLabel.setHorizontalAlignment(SwingConstants.LEFT);
+        
+        current = new JLabel("-");
+        current.setHorizontalAlignment(SwingConstants.RIGHT);
+        
+        max = new JLabel("-");
+        max.setHorizontalAlignment(SwingConstants.RIGHT);
+        
+        heapDumpButton = new JButton("Heap Dump");
+        heapDumpButton.setName("heapDumpButton");
+
+        JScrollPane dumpListScrollPane = new JScrollPane();
+        dumpList = new JList<>();
+        dumpList.setName("heapDumpList");
+        listModel = new DefaultListModel<>();
+        dumpList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        dumpList.setModel(listModel);
+        
+        GroupLayout gl_rightPanel = new GroupLayout(rightPanel);
+        gl_rightPanel.setHorizontalGroup(
+            gl_rightPanel.createParallelGroup(Alignment.TRAILING)
+                .addGroup(gl_rightPanel.createSequentialGroup()
+                    .addContainerGap()
+                    .addGroup(gl_rightPanel.createParallelGroup(Alignment.TRAILING)
+                        .addComponent(dumpListScrollPane, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 173, Short.MAX_VALUE)
+                        .addComponent(heapDumpButton, GroupLayout.DEFAULT_SIZE, 173, Short.MAX_VALUE)
+                        .addGroup(gl_rightPanel.createSequentialGroup()
+                            .addGroup(gl_rightPanel.createParallelGroup(Alignment.TRAILING, false)
+                                .addComponent(maxLabel, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                                .addComponent(currentLabel, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 48, Short.MAX_VALUE))
+                            .addPreferredGap(ComponentPlacement.RELATED)
+                            .addGroup(gl_rightPanel.createParallelGroup(Alignment.TRAILING)
+                                .addComponent(current, GroupLayout.DEFAULT_SIZE, 119, Short.MAX_VALUE)
+                                .addComponent(max, GroupLayout.PREFERRED_SIZE, 119, GroupLayout.PREFERRED_SIZE))))
+                    .addContainerGap())
+        );
+        gl_rightPanel.setVerticalGroup(
+            gl_rightPanel.createParallelGroup(Alignment.LEADING)
+                .addGroup(gl_rightPanel.createSequentialGroup()
+                    .addContainerGap()
+                    .addGroup(gl_rightPanel.createParallelGroup(Alignment.BASELINE)
+                        .addComponent(currentLabel, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE)
+                        .addComponent(current))
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addGroup(gl_rightPanel.createParallelGroup(Alignment.BASELINE)
+                        .addComponent(maxLabel)
+                        .addComponent(max))
+                    .addGap(18)
+                    .addComponent(heapDumpButton)
+                    .addGap(18)
+                    .addComponent(dumpListScrollPane, GroupLayout.DEFAULT_SIZE, 172, Short.MAX_VALUE)
+                    .addContainerGap())
+        );
+        rightPanel.setLayout(gl_rightPanel);
+        setLayout(groupLayout);
+
+        dumpListScrollPane.setViewportView(dumpList);
+    }
+    
+    void setChartPanel(JPanel panel) {
+        leftPanel.removeAll();
+        leftPanel.add(panel);
+        leftPanel.revalidate();
+        repaint();
+    }
+
+    public void setMax(String capacity) {
+        max.setText(capacity);
+    }
+
+    public void setUsed(String used) {
+        current.setText(used);
+    }
+    
+    void addHeapDumperListener(ActionListener listener) {
+        heapDumpButton.addActionListener(listener);
+    }
+
+    void addDumpListListener(ListSelectionListener listener) {
+        dumpList.addListSelectionListener(listener);
+    }
+    
+    public void disableHeapDumperControl() {
+        heapDumpButton.setText("dumping...");
+        heapDumpButton.setEnabled(false);
+    }
+
+    public void enableHeapDumperControl() {
+        heapDumpButton.setText("Heap Dump");
+        heapDumpButton.setEnabled(true);
+    }
+
+    public void addDump(HeapDump dump) {
+        
+        listModel.addElement(dump);
+    }
+
+    public void clearDumpList() {
+        listModel.clear();
+    }
+    
+    public HeapDump getSelectedHeapDump() {
+        return dumpList.getSelectedValue();
+    }
+
+    public void updateHeapDumpList(List<HeapDump> heapDumps) {
+        int numItemsBefore = listModel.getSize();
+        for (HeapDump heapDump : heapDumps) {
+            if (! listModel.contains(heapDump)) {
+                listModel.addElement(heapDump);
+            }
+        }
+        if (numItemsBefore == 0 && listModel.getSize() > 0) {
+            dumpList.repaint();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/SwingHeapDumpDetailsViewProvider.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,50 @@
+/*
+ * 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.vm.heap.analysis.client.swing.internal;
+
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsViewProvider;
+
+public class SwingHeapDumpDetailsViewProvider implements
+        HeapDumpDetailsViewProvider {
+
+    @Override
+    public HeapDumpDetailsView createView() {
+        return new HeapDetailsSwing();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/SwingHeapHistogramViewProvider.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,50 @@
+/*
+ * 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.vm.heap.analysis.client.swing.internal;
+
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramViewProvider;
+
+public class SwingHeapHistogramViewProvider implements
+        HeapHistogramViewProvider {
+
+    @Override
+    public HeapHistogramView createView() {
+        return new HistogramPanel();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/SwingHeapViewProvider.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,49 @@
+/*
+ * 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.vm.heap.analysis.client.swing.internal;
+
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapViewProvider;
+
+public class SwingHeapViewProvider implements HeapViewProvider {
+
+    @Override
+    public HeapView createView() {
+        return new HeapSwingView();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/SwingObjectDetailsViewProvider.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,50 @@
+/*
+ * 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.vm.heap.analysis.client.swing.internal;
+
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
+
+public class SwingObjectDetailsViewProvider implements
+        ObjectDetailsViewProvider {
+
+    @Override
+    public ObjectDetailsView createView() {
+        return new ObjectDetailsPanel();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/main/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/SwingObjectRootsViewProvider.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,49 @@
+/*
+ * 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.vm.heap.analysis.client.swing.internal;
+
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsViewProvider;
+
+public class SwingObjectRootsViewProvider implements ObjectRootsViewProvider {
+
+    @Override
+    public ObjectRootsView createView() {
+        return new ObjectRootsFrame();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ActivatorTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,71 @@
+/*
+ * 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.vm.heap.analysis.client.swing.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.test.StubBundleContext;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapHistogramViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.Activator;
+import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.SwingHeapDumpDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.SwingHeapHistogramViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.SwingHeapViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.SwingObjectDetailsViewProvider;
+import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.SwingObjectRootsViewProvider;
+
+public class ActivatorTest {
+
+    @Test
+    public void verifyStartRegistersViewProvider() throws Exception {
+        StubBundleContext ctx = new StubBundleContext();
+        Activator activator = new Activator();
+        activator.start(ctx);
+        assertTrue(ctx.isServiceRegistered(HeapViewProvider.class.getName(), SwingHeapViewProvider.class));
+        assertTrue(ctx.isServiceRegistered(HeapDumpDetailsViewProvider.class.getName(), SwingHeapDumpDetailsViewProvider.class));
+        assertTrue(ctx.isServiceRegistered(HeapHistogramViewProvider.class.getName(), SwingHeapHistogramViewProvider.class));
+        assertTrue(ctx.isServiceRegistered(ObjectDetailsViewProvider.class.getName(), SwingObjectDetailsViewProvider.class));
+        assertTrue(ctx.isServiceRegistered(ObjectRootsViewProvider.class.getName(), SwingObjectRootsViewProvider.class));
+        assertEquals(5, ctx.getAllServices().size());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapDetailsSwingTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,154 @@
+/*
+ * 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.vm.heap.analysis.client.swing.internal;
+
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.Callable;
+
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+
+import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
+
+import org.fest.swing.annotation.GUITest;
+import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
+import org.fest.swing.edt.GuiActionRunner;
+import org.fest.swing.edt.GuiTask;
+import org.fest.swing.fixture.FrameFixture;
+import org.fest.swing.fixture.JTabbedPaneFixture;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.redhat.thermostat.client.swing.components.EdtHelper;
+import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.HeapDetailsSwing;
+import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.HistogramPanel;
+import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.ObjectDetailsPanel;
+
+@RunWith(CacioFESTRunner.class)
+public class HeapDetailsSwingTest {
+
+    private JFrame frame;
+    private FrameFixture frameFixture;
+    private HeapDetailsSwing view;
+
+    @BeforeClass
+    public static void setUpOnce() {
+        FailOnThreadViolationRepaintManager.install();
+    }
+
+    @Before
+    public void setUp() {
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                view = new HeapDetailsSwing();
+                frame = new JFrame();
+                frame.add(view.getUiComponent());
+
+            }
+        });
+        frameFixture = new FrameFixture(frame);
+    }
+
+    @After
+    public void tearDown() {
+        frameFixture.cleanUp();
+        frameFixture = null;
+    }
+
+    @GUITest
+    @Test
+    public void verifyTabsAdded() throws InvocationTargetException, InterruptedException {
+        frameFixture.show();
+
+        JTabbedPaneFixture tabPane = frameFixture.tabbedPane("tabs");
+        assertNotNull(tabPane);
+
+        HistogramPanel histogramView = mock(HistogramPanel.class);
+        when(histogramView.getUiComponent()).thenReturn(new EdtHelper().callAndWait(new Callable<JPanel>() {
+            @Override
+            public JPanel call() throws Exception {
+                return new JPanel();
+            }
+        }));
+
+        ObjectDetailsPanel objectDetailsView = mock(ObjectDetailsPanel.class);
+        when(objectDetailsView.getUiComponent()).thenReturn(new EdtHelper().callAndWait(new Callable<JPanel>() {
+            @Override
+            public JPanel call() throws Exception {
+                return new JPanel();
+            }
+        }));
+        view.addSubView("test1", histogramView);
+        view.addSubView("test2", objectDetailsView);
+
+        tabPane.requireTabTitles("test1", "test2");
+    }
+
+
+    @GUITest
+    @Test
+    public void verifyAddRemove() throws InvocationTargetException, InterruptedException {
+        frameFixture.show();
+
+        JTabbedPaneFixture tabPane = frameFixture.tabbedPane("tabs");
+        assertNotNull(tabPane);
+
+        HistogramPanel histogramView = mock(HistogramPanel.class);
+        when(histogramView.getUiComponent()).thenReturn(new EdtHelper().callAndWait(new Callable<JPanel>() {
+            @Override
+            public JPanel call() throws Exception {
+                return new JPanel();
+            }
+        }));
+
+        view.addSubView("test1", histogramView);
+
+        tabPane.requireTabTitles("test1");
+
+        view.removeSubView("test1");
+
+        tabPane.requireTabTitles();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapSwingViewTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,147 @@
+/*
+ * 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.vm.heap.analysis.client.swing.internal;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.awt.Container;
+import java.util.Arrays;
+import java.util.List;
+
+import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
+
+import org.fest.swing.annotation.GUITest;
+import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
+import org.fest.swing.edt.GuiActionRunner;
+import org.fest.swing.edt.GuiTask;
+import org.fest.swing.fixture.Containers;
+import org.fest.swing.fixture.FrameFixture;
+import org.fest.swing.fixture.JButtonFixture;
+import org.fest.swing.fixture.JListFixture;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapView.HeapDumperAction;
+import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.HeapSwingView;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+
+@RunWith(CacioFESTRunner.class)
+public class HeapSwingViewTest {
+
+    private HeapSwingView view;
+
+    private FrameFixture frame;
+
+    @BeforeClass
+    public static void setUpOnce() {
+        FailOnThreadViolationRepaintManager.install();
+    }
+
+
+    @Before
+    public void setUp() throws Exception {
+        GuiActionRunner.execute(new GuiTask() {
+            
+            @Override
+            protected void executeInEDT() throws Throwable {
+                view = new HeapSwingView();
+            }
+        });
+        frame = Containers.showInFrame((Container) view.getUiComponent());
+    }
+
+    @After
+    public void tearDown() {
+        frame.cleanUp();
+        frame = null;
+        view = null;
+    }
+
+    @Test
+    @GUITest
+    public void testActivateHeapDump() {
+        @SuppressWarnings("unchecked")
+        ActionListener<HeapDumperAction> l = mock(ActionListener.class);
+        view.addDumperListener(l);
+        JButtonFixture heapDumpButton = frame.button("heapDumpButton");
+        heapDumpButton.click();
+        verify(l).actionPerformed(new ActionEvent<HeapDumperAction>(view, HeapDumperAction.DUMP_REQUESTED));
+    }
+
+    @Test
+    @GUITest
+    public void testNotifyHeapDumpComplete() {
+        final JButtonFixture heapDumpButton = frame.button("heapDumpButton");
+        GuiActionRunner.execute(new GuiTask() {
+            
+            @Override
+            protected void executeInEDT() throws Throwable {
+                heapDumpButton.component().setEnabled(false);
+            }
+        });
+
+        view.notifyHeapDumpComplete();
+        frame.robot.waitForIdle();
+
+        heapDumpButton.requireEnabled();
+    }
+
+    @Test
+    @GUITest
+    public void testUpdateHeapDumpList() {
+        JListFixture heapDumpList = frame.list("heapDumpList");
+        heapDumpList.requireItemCount(0);
+
+        HeapDump heapDump = mock(HeapDump.class);
+        List<HeapDump> heapDumps = Arrays.asList(heapDump);
+
+        view.updateHeapDumpList(heapDumps);
+        frame.robot.waitForIdle();
+        heapDumpList.requireItemCount(1);
+
+        view.updateHeapDumpList(heapDumps);
+        frame.robot.waitForIdle();
+        heapDumpList.requireItemCount(1);
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectDetailsPanelTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,190 @@
+/*
+ * 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.vm.heap.analysis.client.swing.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.swing.JFrame;
+import javax.swing.JTree;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreePath;
+
+import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
+
+import org.fest.swing.annotation.GUITest;
+import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
+import org.fest.swing.edt.GuiActionRunner;
+import org.fest.swing.edt.GuiTask;
+import org.fest.swing.fixture.FrameFixture;
+import org.fest.swing.fixture.JTextComponentFixture;
+import org.fest.swing.fixture.JTreeFixture;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.redhat.thermostat.client.core.views.SearchFieldView;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapObjectUI;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsView.ObjectAction;
+import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.ObjectDetailsPanel;
+import com.sun.tools.hat.internal.model.JavaClass;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+
+@RunWith(CacioFESTRunner.class)
+public class ObjectDetailsPanelTest {
+
+    private JFrame frame;
+    private FrameFixture frameFixture;
+    private ObjectDetailsPanel view;
+    private ActionListener<ObjectAction> listener;
+
+    @BeforeClass
+    public static void setUpOnce() {
+        FailOnThreadViolationRepaintManager.install();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Before
+    public void setUp() {
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                view = new ObjectDetailsPanel();
+                frame = new JFrame();
+                frame.add(view.getUiComponent());
+
+            }
+        });
+        frameFixture = new FrameFixture(frame);
+
+        listener = mock(ActionListener.class);
+        view.addObjectActionListener(listener);
+    }
+
+    @After
+    public void tearDown() {
+        frameFixture.cleanUp();
+        frameFixture = null;
+    }
+
+    @GUITest
+    @Test
+    public void verifySearchWorks() {
+        final String SEARCH_TEXT = "test";
+
+        frameFixture.show();
+
+        JTextComponentFixture searchBox = frameFixture.textBox(SearchFieldView.VIEW_NAME);
+        searchBox.enterText(SEARCH_TEXT);
+
+        verify(listener, times(SEARCH_TEXT.length())).actionPerformed(new ActionEvent<ObjectAction>(view, ObjectAction.SEARCH));
+
+        assertEquals(SEARCH_TEXT, view.getSearchText());
+    }
+
+    @GUITest
+    @Test
+    public void verifyMatchingObjectsWork() {
+        frameFixture.show();
+
+        HeapObjectUI obj1 = new HeapObjectUI("obj1", "obj1");
+        HeapObjectUI obj2 = new HeapObjectUI("obj2", "obj2");
+
+        view.setMatchingObjects(Arrays.asList(obj1, obj2));
+
+        JTreeFixture tree = frameFixture.tree(ObjectDetailsPanel.TREE_NAME);
+
+        TreePath[] paths = getRows(tree.component());
+
+        assertEquals(obj1, getUserObject(paths[0]));
+        assertEquals(obj2, getUserObject(paths[1]));
+
+        tree.selectPath("obj1");
+
+        assertEquals(obj1, view.getSelectedMatchingObject());
+    }
+
+    private static Object getUserObject(TreePath path) {
+        return ((DefaultMutableTreeNode)path.getLastPathComponent()).getUserObject();
+    }
+
+    private static TreePath[] getRows(JTree tree) {
+        List<TreePath> paths = new ArrayList<>();
+        for (int i = 0; i < tree.getRowCount(); i++) {
+            paths.add(tree.getPathForRow(i));
+        }
+        return paths.toArray(new TreePath[0]);
+    }
+
+    @GUITest
+    @Test
+    public void verifySettingObjectDetails() {
+        final String OBJECT_ID = "id";
+        final boolean HEAP_ALLOCATED = true;
+        final int OBJECT_SIZE = 10;
+        final String OBJECT_CLASS = "foo.bar.Baz";
+
+        frameFixture.show();
+
+        JavaClass klass = mock(JavaClass.class);
+        when(klass.getName()).thenReturn(OBJECT_CLASS);
+
+        JavaHeapObject heapObj = mock(JavaHeapObject.class);
+        when(heapObj.getIdString()).thenReturn(OBJECT_ID);
+        when(heapObj.isHeapAllocated()).thenReturn(HEAP_ALLOCATED);
+        when(heapObj.getSize()).thenReturn(OBJECT_SIZE);
+        when(heapObj.getClazz()).thenReturn(klass);
+
+        view.setObjectDetails(heapObj);
+
+        JTextComponentFixture textBox = frameFixture.textBox(ObjectDetailsPanel.DETAILS_NAME);
+        String expected = "Object ID:" + OBJECT_ID  + "\nType:" + OBJECT_CLASS + "\nSize:" + OBJECT_SIZE + " bytes\nHeap allocated:" + HEAP_ALLOCATED + "\n";
+        assertEquals(expected, textBox.text());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectRootsFrameTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,191 @@
+/*
+ * 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.vm.heap.analysis.client.swing.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.JTree;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreePath;
+
+import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
+
+import org.fest.swing.annotation.GUITest;
+import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
+import org.fest.swing.edt.GuiActionRunner;
+import org.fest.swing.edt.GuiQuery;
+import org.fest.swing.fixture.FrameFixture;
+import org.fest.swing.fixture.JTextComponentFixture;
+import org.fest.swing.fixture.JTreeFixture;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.vm.heap.analysis.client.core.HeapObjectUI;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsView;
+import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsView.Action;
+import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.ObjectRootsFrame;
+
+@RunWith(CacioFESTRunner.class)
+public class ObjectRootsFrameTest {
+
+    private ObjectRootsFrame frame;
+    private FrameFixture frameFixture;
+
+    @BeforeClass
+    public static void setUpOnce() {
+        FailOnThreadViolationRepaintManager.install();
+    }
+
+    @Before
+    public void setUp() {
+        frame = GuiActionRunner.execute(new GuiQuery<ObjectRootsFrame>() {
+            @Override
+            protected ObjectRootsFrame executeInEDT() throws Throwable {
+                return new ObjectRootsFrame();
+            }
+        });
+        frameFixture = new FrameFixture(frame);
+    }
+
+    @After
+    public void tearDown() {
+        frameFixture.cleanUp();
+        frameFixture = null;
+        frame.hideView();
+    }
+
+    @GUITest
+    @Test
+    public void verifyShowHide() {
+        frame.showView();
+
+        frameFixture.requireVisible();
+
+        frame.hideView();
+
+        frameFixture.requireNotVisible();
+    }
+
+    @GUITest
+    @Test
+    public void verifySetPath() {
+        List<HeapObjectUI> path = new ArrayList<>();
+        path.add(new HeapObjectUI("test", "test"));
+        path.add(new HeapObjectUI("test2", "test2"));
+        frame.setPathToRoot(path);
+
+        frame.showView();
+
+        frameFixture.requireVisible();
+
+        JTreeFixture tree = frameFixture.tree(ObjectRootsFrame.TREE_NAME);
+
+        TreePath[] paths = getRows(tree.component());
+
+        assertEquals(path.get(0), getUserObject(paths[0]));
+        assertEquals(path.get(1), getUserObject(paths[1]));
+    }
+
+    private static Object getUserObject(TreePath path) {
+        return ((DefaultMutableTreeNode)path.getLastPathComponent()).getUserObject();
+    }
+
+    private static TreePath[] getRows(JTree tree) {
+        List<TreePath> paths = new ArrayList<>();
+        for (int i = 0; i < tree.getRowCount(); i++) {
+            paths.add(tree.getPathForRow(i));
+        }
+        return paths.toArray(new TreePath[0]);
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @GUITest
+    @Test
+    public void verifyTreeInteraction() {
+        frame.showView();
+
+        frameFixture.requireVisible();
+
+        ActionListener<ObjectRootsView.Action> listener = mock(ActionListener.class);
+        frame.addActionListener(listener);
+
+        List<HeapObjectUI> path = new ArrayList<>();
+        path.add(new HeapObjectUI("test", "test"));
+        frame.setPathToRoot(path);
+
+        JTreeFixture tree = frameFixture.tree(ObjectRootsFrame.TREE_NAME);
+        tree.selectRow(0);
+
+        ArgumentCaptor<ActionEvent> argCaptor = ArgumentCaptor.forClass(ActionEvent.class);
+        // We really want to verify that there's exactly one actionPerformend() call.
+        // If there are more events (such as VISIBLE events) fired, this may be a recipe
+        // for desaster if visble events trigger other actions, such as spawning a thread or
+        // starting/stopping a timer.
+        verify(listener).actionPerformed(argCaptor.capture());
+
+        assertEquals(frame, argCaptor.getValue().getSource());
+        
+        assertEquals(Action.OBJECT_SELECTED, argCaptor.getValue().getActionId());
+        assertEquals(path.get(0), argCaptor.getValue().getPayload());
+    }
+
+    @GUITest
+    @Test
+    public void verifySetDetails() {
+        String detailsText = "foo-bar";
+        frame.setObjectDetails(detailsText);
+
+        frame.showView();
+
+        frameFixture.requireVisible();
+
+        JTextComponentFixture textBox = frameFixture.textBox(ObjectRootsFrame.DETAILS_NAME);
+        textBox.requireText(detailsText);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/pom.xml	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,149 @@
+<?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>
+    <artifactId>thermostat-vm-heap-analysis</artifactId>
+    <groupId>com.redhat.thermostat</groupId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>thermostat-vm-heap-analysis-command</artifactId>
+  <packaging>bundle</packaging>
+  <name>Thermostat VM Heap Analysis Command plugin</name>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-SymbolicName>com.redhat.thermostat.vm.heap.analysis.command</Bundle-SymbolicName>
+            <Export-Package>
+               com.redhat.thermostat.vm.heap.analysis.command,
+               com.redhat.thermostat.vm.heap.analysis.command.locale
+            </Export-Package>
+            <Private-Package>
+               com.redhat.thermostat.vm.heap.analysis.command.internal
+            </Private-Package>
+            <Bundle-Activator>com.redhat.thermostat.vm.heap.analysis.command.internal.Activator</Bundle-Activator>
+            <!-- Do not autogenerate uses clauses in Manifests -->
+            <_nouses>true</_nouses>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-mockito</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-client-command</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-tools</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-test</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-vm-heap-analysis-common</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-vm-heap-analysis-agent</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>com.sun</groupId>
+      <artifactId>tools</artifactId>
+      <scope>system</scope>
+      <systemPath>${java.home}/../lib/tools.jar</systemPath>
+    </dependency>
+    
+  </dependencies>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/FindRoot.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,94 @@
+/*
+ * 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.vm.heap.analysis.command;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+
+public class FindRoot {
+
+    private Set<JavaHeapObject> visitedObjects;
+
+    public Collection<HeapPath<JavaHeapObject>> findShortestPathsToRoot(JavaHeapObject obj, boolean findAll) {
+        HeapPath<JavaHeapObject> path = new HeapPath<>(obj);
+        List<HeapPath<JavaHeapObject>> pathsSoFar = new LinkedList<>();
+        pathsSoFar.add(path);
+        visitedObjects = new HashSet<>();
+        return findShortestPathToRoot(pathsSoFar, findAll);
+    }
+
+    private Collection<HeapPath<JavaHeapObject>> findShortestPathToRoot(List<HeapPath<JavaHeapObject>> pathsSoFar, boolean findAll) {
+        List<HeapPath<JavaHeapObject>> newPaths = new LinkedList<>();
+        Collection<HeapPath<JavaHeapObject>> roots = new ArrayList<>();
+        for (HeapPath<JavaHeapObject> path : pathsSoFar) {
+            JavaHeapObject last = path.getNode();
+            if (visitedObjects.contains(last)) {
+                continue;
+            }
+            @SuppressWarnings("rawtypes")
+            Enumeration referrers = last.getReferers();
+            while (referrers.hasMoreElements()) {
+                JavaHeapObject referrer = (JavaHeapObject) referrers.nextElement();
+                HeapPath<JavaHeapObject> newPath = new HeapPath<>(referrer, path);
+                newPaths.add(newPath);
+                if (referrer.getRoot() != null) {
+                    roots.add(newPath);
+                    if (! findAll) {
+                        return roots;
+                    }
+                }
+            }
+            visitedObjects.add(last);
+        }
+        if (newPaths.isEmpty()) {
+            return roots;
+        } else {
+            Collection<HeapPath<JavaHeapObject>> foundRoots = findShortestPathToRoot(newPaths, findAll);
+            roots.addAll(foundRoots);
+            return roots;
+        }
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/HeapPath.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,100 @@
+/*
+ * 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.vm.heap.analysis.command;
+
+import java.util.Iterator;
+
+public class HeapPath<T> implements Iterable<T> {
+
+    private static class HeapPathIterator<T> implements Iterator<T> {
+
+        private HeapPath<T> path;
+
+        HeapPathIterator(HeapPath<T> path) {
+            this.path = path;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return path != null;
+        }
+
+        @Override
+        public T next() {
+            T next = path.node;
+            path = path.path;
+            return next;
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+    }
+
+    private HeapPath<T> path;
+    private T node;
+    private int length;
+
+    HeapPath(T head) {
+        this(head, null);
+    }
+
+    HeapPath(T node, HeapPath<T> path) {
+        this.node = node;
+        this.path = path;
+        if (path != null) {
+            length = path.length + 1;
+        } else {
+            length = 1;
+        }
+    }
+
+    @Override
+    public Iterator<T> iterator() {
+        return new HeapPathIterator<T>(this);
+    }
+
+    T getNode() {
+        return node;
+    }
+
+    int getLength() {
+        return length;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/Activator.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,65 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import java.util.ServiceLoader;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+import com.redhat.thermostat.common.cli.Command;
+import com.redhat.thermostat.common.cli.CommandRegistry;
+import com.redhat.thermostat.common.cli.CommandRegistryImpl;
+
+public class Activator implements BundleActivator {
+
+    private CommandRegistry reg;
+
+    @Override
+    public void start(final BundleContext context) throws Exception {
+        reg = new CommandRegistryImpl(context);
+        ServiceLoader<Command> cmds = ServiceLoader.load(Command.class,
+                getClass().getClassLoader());
+        reg.registerCommands(cmds);
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        reg.unregisterCommands();
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/DumpHeapCommand.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,113 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import java.util.concurrent.Semaphore;
+
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.HostVMArguments;
+import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.vm.heap.analysis.command.locale.LocaleResources;
+
+
+public class DumpHeapCommand extends SimpleCommand {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+    private static final String NAME = "dump-heap";
+
+    private final OSGIUtils serviceProvider;
+    private final DumpHeapHelper implementation;
+
+    public DumpHeapCommand() {
+        this(OSGIUtils.getInstance(), new DumpHeapHelper());
+    }
+
+    DumpHeapCommand(OSGIUtils serviceProvider, DumpHeapHelper impl) {
+        this.serviceProvider = serviceProvider;
+        this.implementation = impl;
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public void run(final CommandContext ctx) throws CommandException {
+        final HostVMArguments args = new HostVMArguments(ctx.getArguments());
+
+        final CommandException[] ex = new CommandException[1];
+        final Semaphore s = new Semaphore(0);
+        Runnable successHandler = new Runnable() {
+            @Override
+            public void run() {
+                ctx.getConsole().getOutput().println(translator.localize(LocaleResources.COMMAND_HEAP_DUMP_DONE));
+                s.release();
+            }
+        };
+        Runnable errorHandler = new Runnable() {
+            public void run() {
+                ex[0] = new CommandException(translator.localize(
+                        LocaleResources.HEAP_DUMP_ERROR, args.getHost()
+                                .getStringID(), args.getVM().getStringID()));
+                s.release();
+            }
+        };
+
+        AgentInfoDAO service = serviceProvider.getService(AgentInfoDAO.class);
+        if (service == null) {
+            throw new CommandException("Unable to access agent information");
+        }
+        implementation.execute(service, args.getVM(), successHandler, errorHandler);
+        serviceProvider.ungetService(AgentInfoDAO.class, service);
+
+        try {
+            s.acquire();
+        } catch (InterruptedException e) {
+            // Nothing to do here, just return ASAP.
+        }
+        
+        if (ex[0] != null) {
+            throw ex[0];
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/DumpHeapHelper.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,99 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import java.net.InetSocketAddress;
+
+import com.redhat.thermostat.client.command.RequestQueue;
+import com.redhat.thermostat.common.command.Request;
+import com.redhat.thermostat.common.command.Request.RequestType;
+import com.redhat.thermostat.common.command.RequestResponseListener;
+import com.redhat.thermostat.common.command.Response;
+import com.redhat.thermostat.common.command.Response.ResponseType;
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+
+public class DumpHeapHelper {
+    
+    private static final String RECEIVER_CLASS_NAME = "com.redhat.thermostat.vm.heap.analysis.agent.internal.HeapDumpReceiver";
+    private static final String VM_ID_PARAM = "vmId";
+
+    private class HeapDumpListener implements RequestResponseListener {
+
+        private Runnable successAction;
+        private Runnable failureAction;
+
+        private HeapDumpListener(Runnable heapDumpSuccessfulAction, Runnable heapDumpFailureAction) {
+            this.successAction = heapDumpSuccessfulAction;
+            this.failureAction = heapDumpFailureAction;
+        }
+
+        @Override
+        public void fireComplete(Request request, Response response) {
+            if (response.getType() == ResponseType.ERROR) {
+                if (failureAction != null) {
+                    failureAction.run();
+                }
+            } else {
+                if (successAction != null) {
+                    successAction.run();
+                }
+            }
+        }
+
+    }
+
+    public void execute(AgentInfoDAO agentInfoDAO, VmRef reference, Runnable heapDumpSuccessAction, Runnable heapDumpFailureAction) {
+
+        HostRef targetHostRef = reference.getAgent();
+        String address = agentInfoDAO.getAgentInformation(targetHostRef).getConfigListenAddress();
+        
+        String [] host = address.split(":");
+        InetSocketAddress target = new InetSocketAddress(host[0], Integer.parseInt(host[1]));
+        Request req = new Request(RequestType.RESPONSE_EXPECTED, target);
+        req.setReceiver(RECEIVER_CLASS_NAME);
+        req.setParameter(VM_ID_PARAM, reference.getIdString());
+        req.addListener(new HeapDumpListener(heapDumpSuccessAction, heapDumpFailureAction));
+
+        RequestQueue queue = OSGIUtils.getInstance().getService(RequestQueue.class);
+        queue.putRequest(req);
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/FindObjectsCommand.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,144 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import java.util.Collection;
+import java.util.List;
+
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.cli.TableRenderer;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.storage.model.HeapInfo;
+import com.redhat.thermostat.vm.heap.analysis.command.locale.LocaleResources;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+
+public class FindObjectsCommand extends SimpleCommand {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private static final String HEAP_ID_ARG = "heapId";
+    private static final String LIMIT_ARG = "limit";
+    private static final String NAME = "find-objects";
+    private static final String HEADER_OBJECT_ID = translator.localize(LocaleResources.HEADER_OBJECT_ID);
+    private static final String HEADER_TYPE = translator.localize(LocaleResources.HEADER_OBJECT_TYPE);
+    private static final int DEFAULT_LIMIT = 10;
+
+    private OSGIUtils serviceProvider;
+
+    public FindObjectsCommand() {
+        this(OSGIUtils.getInstance());
+    }
+
+    FindObjectsCommand(OSGIUtils serviceProvider) {
+        this.serviceProvider = serviceProvider;
+    }
+
+    @Override
+    public void run(CommandContext ctx) throws CommandException {
+
+        HeapDAO heapDAO = serviceProvider.getServiceAllowNull(HeapDAO.class);
+        if (heapDAO == null) {
+            throw new CommandException(translator.localize(LocaleResources.HEAP_SERVICE_UNAVAILABLE));
+        }
+        try {
+            run(ctx, heapDAO);
+        } finally {
+            serviceProvider.ungetService(HeapDAO.class, heapDAO);
+            heapDAO = null;
+        }
+    }
+
+    private void run(CommandContext ctx, HeapDAO heapDAO) throws CommandException {
+        String heapId = ctx.getArguments().getArgument(HEAP_ID_ARG);
+        HeapInfo heapInfo = heapDAO.getHeapInfo(heapId);
+        if (heapInfo == null) {
+            ctx.getConsole().getOutput().println(translator.localize(LocaleResources.HEAP_ID_NOT_FOUND, heapId));
+            return;
+        }
+        HeapDump heapDump = heapDAO.getHeapDump(heapInfo);
+        if (heapDump == null) {
+            ctx.getConsole().getOutput().println(translator.localize(LocaleResources.HEAP_ID_NOT_FOUND, heapId));
+            return;
+        }
+
+        List<String> terms = ctx.getArguments().getNonOptionArguments();
+        if (terms.size() == 0) {
+            ctx.getConsole().getOutput().println(translator.localize(LocaleResources.SEARCH_TERM_REQUIRED));
+            return;
+        }
+        String searchTerm = terms.get(0);
+        if (searchTerm.trim().length() == 0) {
+            ctx.getConsole().getOutput().println(translator.localize(LocaleResources.SEARCH_TERM_REQUIRED));
+            return;
+        }
+
+        String limitArg = ctx.getArguments().getArgument(LIMIT_ARG);
+        int limit = parseLimit(limitArg);
+        Collection<String> results = heapDump.searchObjects(searchTerm, limit);
+        TableRenderer table = new TableRenderer(2);
+        table.printLine(HEADER_OBJECT_ID, HEADER_TYPE);
+        for (String objectId : results) {
+            JavaHeapObject obj = heapDump.findObject(objectId);
+            String id = obj.getIdString();
+            String className = obj.getClazz().getName();
+            table.printLine(id, className);
+        }
+        table.render(ctx.getConsole().getOutput());
+    }
+
+    private int parseLimit(String limitArg) throws CommandException {
+        int limit = DEFAULT_LIMIT;
+        if (limitArg != null) {
+            try {
+                limit = Integer.parseInt(limitArg);
+            } catch (NumberFormatException ex) {
+                throw new CommandException(translator.localize(LocaleResources.INVALID_LIMIT, limitArg));
+            }
+        }
+        return limit;
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/FindRootCommand.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,144 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import java.io.PrintStream;
+import java.util.Collection;
+import java.util.Iterator;
+
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.vm.heap.analysis.command.FindRoot;
+import com.redhat.thermostat.vm.heap.analysis.command.HeapPath;
+import com.redhat.thermostat.vm.heap.analysis.command.locale.LocaleResources;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+import com.sun.tools.hat.internal.model.Root;
+import com.sun.tools.hat.internal.model.Snapshot;
+
+public class FindRootCommand extends SimpleCommand {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private static final String ALL_ARG = "all";
+    private static final String NAME = "find-root";
+
+    private OSGIUtils serviceProvider;
+
+    public FindRootCommand() {
+        this(OSGIUtils.getInstance());
+    }
+
+    FindRootCommand(OSGIUtils serviceProvider) {
+        this.serviceProvider = serviceProvider;
+    }
+
+    @Override
+    public void run(CommandContext ctx) throws CommandException {
+        HeapDAO heapDao = serviceProvider.getServiceAllowNull(HeapDAO.class);
+        if (heapDao == null) {
+            throw new CommandException(translator.localize(LocaleResources.HEAP_SERVICE_UNAVAILABLE));
+        }
+
+        try {
+            run(ctx, heapDao);
+        } finally {
+            serviceProvider.ungetService(HeapDAO.class, heapDao);
+        }
+    }
+
+    private void run(CommandContext ctx, HeapDAO heapDao) throws CommandException {
+        ObjectCommandHelper objCmdHelper = new ObjectCommandHelper(ctx, heapDao);
+        HeapDump heapDump = objCmdHelper.getHeapDump();
+        Snapshot snapshot = heapDump.getSnapshot();
+        JavaHeapObject obj = objCmdHelper.getJavaHeapObject();
+        boolean findAll = ctx.getArguments().hasArgument(ALL_ARG);
+        FindRoot findRoot = new FindRoot();
+        Collection<HeapPath<JavaHeapObject>> pathsToRoot = findRoot.findShortestPathsToRoot(obj, findAll);
+        PrintStream out = ctx.getConsole().getOutput();
+        if (pathsToRoot.isEmpty()) {
+            out.println(translator.localize(LocaleResources.COMMAND_FIND_ROOT_NO_ROOT_FOUND, PrintObjectUtils.objectToString(obj)));
+        } else {
+            printPathsToRoot(snapshot, pathsToRoot, out);
+        }
+    }
+
+    private void printPathsToRoot(Snapshot snapshot, Collection<HeapPath<JavaHeapObject>> pathsToRoot, PrintStream out) {
+        for (HeapPath<JavaHeapObject> path : pathsToRoot) {
+            printPathToRoot(snapshot, path, out);
+            out.println();
+        }
+    }
+
+    private void printPathToRoot(Snapshot snapshot, HeapPath<JavaHeapObject> pathToRoot, PrintStream out) {
+        // Print root.
+        Iterator<JavaHeapObject> i = pathToRoot.iterator();
+        JavaHeapObject last = i.next();
+        Root root = last.getRoot();
+        out.println(root.getDescription() + " -> " + PrintObjectUtils.objectToString(last));
+        // Print reference 'tree'.
+        int indentation = 0;
+        while (i.hasNext()) {
+            JavaHeapObject next = i.next();
+            printIndentation(out, indentation);
+            out.print("\u2514");
+            out.print(last.describeReferenceTo(next, snapshot));
+            out.print(" in ");
+            out.print(PrintObjectUtils.objectToString(last));
+            out.print(" -> ");
+            out.println(PrintObjectUtils.objectToString(next));
+            last = next;
+            indentation++;
+        }
+    }
+
+    private void printIndentation(PrintStream out, int indentation) {
+        for (int i = 0; i < indentation; i++) {
+            out.print(" ");
+        }
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/HeapNotFoundException.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,50 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import com.redhat.thermostat.common.cli.CommandException;
+
+@SuppressWarnings("serial")
+public class HeapNotFoundException extends CommandException {
+
+    private static final String MESSAGE_TEMPLATE = "Heap ID not found: ";
+
+    HeapNotFoundException(String heapId) {
+        super(MESSAGE_TEMPLATE + heapId);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ListHeapDumpsCommand.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,135 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.HostVMArguments;
+import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.cli.TableRenderer;
+import com.redhat.thermostat.common.dao.HostInfoDAO;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.storage.model.HeapInfo;
+import com.redhat.thermostat.vm.heap.analysis.command.locale.LocaleResources;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+
+public class ListHeapDumpsCommand extends SimpleCommand {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private static final String NAME = "list-heap-dumps";
+
+    private static final String[] COLUMN_NAMES = {
+        translator.localize(LocaleResources.HEADER_HOST_ID),
+        translator.localize(LocaleResources.HEADER_VM_ID),
+        translator.localize(LocaleResources.HEADER_HEAP_ID),
+        translator.localize(LocaleResources.HEADER_TIMESTAMP),
+    };
+
+    private final OSGIUtils serviceProvider;
+
+    public ListHeapDumpsCommand() {
+        this(OSGIUtils.getInstance());
+    }
+
+    /** For tests only */
+    ListHeapDumpsCommand(OSGIUtils serviceProvider) {
+        this.serviceProvider = serviceProvider;
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public void run(CommandContext ctx) throws CommandException {
+        HostVMArguments args = new HostVMArguments(ctx.getArguments(), false, false);
+
+        TableRenderer renderer = new TableRenderer(4);
+
+        renderer.printLine(COLUMN_NAMES);
+
+        HostInfoDAO hostDAO = serviceProvider.getServiceAllowNull(HostInfoDAO.class);
+        if (hostDAO == null) {
+            throw new CommandException(translator.localize(LocaleResources.HOST_SERVICE_UNAVAILABLE));
+        }
+
+        VmInfoDAO vmDAO = serviceProvider.getServiceAllowNull(VmInfoDAO.class);
+        if (vmDAO == null) {
+            throw new CommandException(translator.localize(LocaleResources.VM_SERVICE_UNAVAILABLE));
+        }
+
+        HeapDAO heapDAO = serviceProvider.getServiceAllowNull(HeapDAO.class);
+        if (heapDAO == null) {
+            throw new CommandException(translator.localize(LocaleResources.HEAP_SERVICE_UNAVAILABLE));
+        }
+
+        Collection<HostRef> hosts = args.getHost() != null ? Arrays.asList(args.getHost()) : hostDAO.getHosts();
+        for (HostRef hostRef : hosts) {
+            Collection<VmRef> vms = args.getVM() != null ? Arrays.asList(args.getVM()) : vmDAO.getVMs(hostRef);
+            for (VmRef vmRef : vms) {
+                printDumpsForVm(heapDAO, hostRef, vmRef, renderer);
+            }
+        }
+
+        serviceProvider.ungetService(HeapDAO.class, heapDAO);
+        serviceProvider.ungetService(VmInfoDAO.class, vmDAO);
+        serviceProvider.ungetService(HostInfoDAO.class, hostDAO);
+
+        renderer.render(ctx.getConsole().getOutput());
+    }
+
+    private void printDumpsForVm(HeapDAO heapDAO, HostRef hostRef, VmRef vmRef, TableRenderer renderer) {
+        Collection<HeapInfo> infos = heapDAO.getAllHeapInfo(vmRef);
+        for (HeapInfo info : infos) {
+            renderer.printLine(hostRef.getStringID(),
+                               vmRef.getStringID(),
+                               info.getHeapId(),
+                               new Date(info.getTimeStamp()).toString());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ObjectCommandHelper.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,88 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import com.redhat.thermostat.common.cli.Arguments;
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.storage.model.HeapInfo;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+
+public class ObjectCommandHelper {
+
+    private static final String OBJECT_ID_ARG = "objectId";
+    private static final String HEAP_ID_ARG = "heapId";
+
+    private CommandContext ctx;
+    private HeapDAO dao;
+    private HeapDump heapDump;
+
+    public ObjectCommandHelper(CommandContext ctx, HeapDAO dao) {
+        this.ctx = ctx;
+        this.dao = dao;
+    }
+
+    public HeapDump getHeapDump() throws CommandException {
+        if (heapDump == null) {
+            loadHeapDump();
+        }
+        return heapDump;
+    }
+
+    private void loadHeapDump() throws CommandException {
+        Arguments args = ctx.getArguments();
+        String heapId = args.getArgument(HEAP_ID_ARG);
+        HeapInfo heapInfo = dao.getHeapInfo(heapId);
+        if (heapInfo == null) {
+            throw new HeapNotFoundException(heapId);
+        }
+        heapDump = dao.getHeapDump(heapInfo);
+    }
+
+    public JavaHeapObject getJavaHeapObject() throws CommandException {
+        HeapDump heapDump = getHeapDump();
+        Arguments args = ctx.getArguments();
+        String objectId = args.getArgument(OBJECT_ID_ARG);
+        JavaHeapObject obj = heapDump.findObject(objectId);
+        if (obj == null) {
+            throw new ObjectNotFoundException(objectId);
+        }
+        return obj;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ObjectInfoCommand.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,146 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import java.io.PrintStream;
+import java.util.Enumeration;
+
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.cli.TableRenderer;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.vm.heap.analysis.command.locale.LocaleResources;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+import com.sun.tools.hat.internal.model.JavaClass;
+import com.sun.tools.hat.internal.model.JavaField;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+import com.sun.tools.hat.internal.model.JavaHeapObjectVisitor;
+import com.sun.tools.hat.internal.model.Snapshot;
+
+public class ObjectInfoCommand extends SimpleCommand {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private static final String NAME = "object-info";
+
+    private OSGIUtils serviceProvider;
+    private Snapshot snapshot;
+
+    public ObjectInfoCommand() {
+        this(OSGIUtils.getInstance());
+    }
+
+    ObjectInfoCommand(OSGIUtils serviceProvider) {
+        this.serviceProvider = serviceProvider;
+    }
+
+    @Override
+    public void run(CommandContext ctx) throws CommandException {
+        HeapDAO heapDao = serviceProvider.getServiceAllowNull(HeapDAO.class);
+        if (heapDao == null) {
+            throw new CommandException(translator.localize(LocaleResources.HEAP_SERVICE_UNAVAILABLE));
+        }
+
+        try {
+            run(ctx, heapDao);
+        } finally {
+            serviceProvider.ungetService(HeapDAO.class, heapDao);
+        }
+    }
+
+    private void run(CommandContext ctx, HeapDAO heapDao) throws CommandException {
+        ObjectCommandHelper objCmdHelper = new ObjectCommandHelper(ctx, heapDao);
+        HeapDump heapDump = objCmdHelper.getHeapDump();
+        snapshot = heapDump.getSnapshot();
+        JavaHeapObject obj = objCmdHelper.getJavaHeapObject();
+        TableRenderer table = new TableRenderer(2);
+        table.printLine(translator.localize(LocaleResources.COMMAND_OBJECT_INFO_OBJECT_ID), obj.getIdString());
+        table.printLine(translator.localize(LocaleResources.COMMAND_OBJECT_INFO_TYPE), obj.getClazz().getName());
+        table.printLine(translator.localize(LocaleResources.COMMAND_OBJECT_INFO_SIZE), String.valueOf(obj.getSize()) + " bytes");
+        table.printLine(translator.localize(LocaleResources.COMMAND_OBJECT_INFO_HEAP_ALLOCATED), String.valueOf(obj.isHeapAllocated()));
+        table.printLine(translator.localize(LocaleResources.COMMAND_OBJECT_INFO_REFERENCES), "");
+        printReferences(table, obj);
+        table.printLine(translator.localize(LocaleResources.COMMAND_OBJECT_INFO_REFERRERS), "");
+        printReferrers(table, obj);
+
+        PrintStream out = ctx.getConsole().getOutput();
+        table.render(out);
+
+    }
+
+    private void printReferences(final TableRenderer table, final JavaHeapObject obj) {
+        JavaHeapObjectVisitor v = new JavaHeapObjectVisitor() {
+            
+            @Override
+            public void visit(JavaHeapObject ref) {
+                table.printLine("", describeReference(obj, ref) + " -> " + PrintObjectUtils.objectToString(ref));
+            }
+            
+            @Override
+            public boolean mightExclude() {
+                return false;
+            }
+            
+            @Override
+            public boolean exclude(JavaClass arg0, JavaField arg1) {
+                return false;
+            }
+        };
+        obj.visitReferencedObjects(v);
+    }
+
+    private void printReferrers(TableRenderer table, JavaHeapObject obj) {
+        Enumeration<?> referrers = obj.getReferers();
+        while (referrers.hasMoreElements()) {
+            JavaHeapObject ref = (JavaHeapObject) referrers.nextElement();
+            table.printLine("", PrintObjectUtils.objectToString(ref) + " -> " + describeReference(ref, obj));
+        }
+    }
+
+    private String describeReference(JavaHeapObject from, JavaHeapObject to) {
+        return "[" + from.describeReferenceTo(to, snapshot) + "]";
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ObjectNotFoundException.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,50 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import com.redhat.thermostat.common.cli.CommandException;
+
+@SuppressWarnings("serial")
+public class ObjectNotFoundException extends CommandException {
+
+    private static final String MESSAGE_TEMPLATE = "Object not found: ";
+
+    ObjectNotFoundException(String objectId) {
+        super(MESSAGE_TEMPLATE + objectId);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/PrintObjectUtils.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,46 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+
+public class PrintObjectUtils {
+
+    public static String objectToString(JavaHeapObject obj) {
+        return obj.getClazz().getName() + "@" + obj.getIdString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/SaveHeapDumpToFileCommand.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,136 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import com.redhat.thermostat.common.cli.Arguments;
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.common.utils.StreamUtils;
+import com.redhat.thermostat.storage.model.HeapInfo;
+import com.redhat.thermostat.vm.heap.analysis.command.locale.LocaleResources;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+
+public class SaveHeapDumpToFileCommand extends SimpleCommand {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private static final String NAME = "save-heap-dump-to-file";
+
+    private static final String HEAP_ID_ARGUMENT = "heapId";
+    private static final String FILE_NAME_ARGUMENT = "file";
+
+    private final FileStreamCreator creator;
+    private final OSGIUtils serviceProvider;
+
+    public SaveHeapDumpToFileCommand() {
+        this(OSGIUtils.getInstance(), new FileStreamCreator());
+    }
+
+    SaveHeapDumpToFileCommand(OSGIUtils serviceProvider, FileStreamCreator creator) {
+        this.serviceProvider = serviceProvider;
+        this.creator = creator;
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+
+    public void run(CommandContext ctx) throws CommandException {
+        HeapDAO heapDAO = serviceProvider.getServiceAllowNull(HeapDAO.class);
+        try {
+            run(ctx, heapDAO);
+        } finally {
+            serviceProvider.ungetService(HeapDAO.class, heapDAO);
+            heapDAO = null;
+        }
+    }
+
+    private void run(CommandContext ctx, HeapDAO heapDAO) throws CommandException {
+        Arguments args = ctx.getArguments();
+        String heapId = args.getArgument(HEAP_ID_ARGUMENT);
+        if (heapId == null) {
+            throw new CommandException(translator.localize(LocaleResources.HEAP_ID_REQUIRED));
+        }
+        String filename = args.getArgument(FILE_NAME_ARGUMENT);
+        if (filename == null) {
+            throw new CommandException(translator.localize(LocaleResources.FILE_REQUIRED));
+        }
+
+        HeapInfo heapInfo = heapDAO.getHeapInfo(heapId);
+        try (InputStream heapStream = heapDAO.getHeapDumpData(heapInfo)) {
+            if (heapStream != null) {
+                try {
+                    saveHeapDump(heapStream, filename);
+                    ctx.getConsole().getOutput().println(translator.localize(LocaleResources.COMMAND_SAVE_HEAP_DUMP_SAVED_TO_FILE, filename));
+                } catch (IOException e) {
+                    ctx.getConsole().getOutput().println(translator.localize(LocaleResources.COMMAND_SAVE_HEAP_DUMP_ERROR_SAVING, e.getMessage()));
+                }
+            } else {
+                ctx.getConsole().getOutput().println(translator.localize(LocaleResources.HEAP_ID_NOT_FOUND, heapId));
+            }
+        } catch (IOException e) {
+            throw new CommandException(translator.localize(LocaleResources.COMMAND_SAVE_HEAP_DUMP_ERROR_CLOSING_STREAM, e.getMessage()));
+        }
+    }
+
+    private void saveHeapDump(InputStream heapStream, String filename) throws FileNotFoundException, IOException {
+        try (BufferedInputStream bis = new BufferedInputStream(heapStream);
+             BufferedOutputStream bout = new BufferedOutputStream(creator.createOutputStream(filename))) {
+            StreamUtils.copyStream(bis, bout);
+        }
+    }
+
+    static class FileStreamCreator {
+        public OutputStream createOutputStream(String filename) throws FileNotFoundException {
+            return new FileOutputStream(filename);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ShowHeapHistogramCommand.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,116 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import java.io.PrintStream;
+
+import com.redhat.thermostat.common.cli.Arguments;
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleCommand;
+import com.redhat.thermostat.common.cli.TableRenderer;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.storage.model.HeapInfo;
+import com.redhat.thermostat.vm.heap.analysis.command.locale.LocaleResources;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import com.redhat.thermostat.vm.heap.analysis.common.HistogramRecord;
+import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram;
+
+public class ShowHeapHistogramCommand extends SimpleCommand {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private static final String NAME = "show-heap-histogram";
+
+    private OSGIUtils serviceProvider;
+
+    public ShowHeapHistogramCommand() {
+        this(OSGIUtils.getInstance());
+    }
+
+    ShowHeapHistogramCommand(OSGIUtils serviceProvider) {
+        this.serviceProvider = serviceProvider;
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public void run(CommandContext ctx) throws CommandException {
+        HeapDAO heapDAO = serviceProvider.getServiceAllowNull(HeapDAO.class);
+        if (heapDAO == null) {
+            throw new CommandException(translator.localize(LocaleResources.HEAP_SERVICE_UNAVAILABLE));
+        }
+
+        try {
+            run(ctx, heapDAO);
+        } finally {
+            serviceProvider.ungetService(HeapDAO.class, heapDAO);
+        }
+    }
+
+    private void run(CommandContext ctx, HeapDAO heapDAO) throws CommandException {
+        Arguments args = ctx.getArguments();
+        String heapId = args.getArgument("heapId");
+
+        HeapInfo heapInfo = heapDAO.getHeapInfo(heapId);
+        if (heapInfo == null) {
+            ctx.getConsole().getOutput().println(translator.localize(LocaleResources.HEAP_ID_NOT_FOUND, heapId));
+            return;
+        }
+
+        ObjectHistogram histogram = heapDAO.getHistogram(heapInfo);
+        if (histogram == null) {
+            ctx.getConsole().getOutput().println(translator.localize(LocaleResources.HEAP_ID_NOT_FOUND, heapId));
+            return;
+        } else {
+            printHeapHistogram(histogram, ctx.getConsole().getOutput());
+        }
+    }
+
+    private void printHeapHistogram(ObjectHistogram histogram, PrintStream out) {
+        TableRenderer table = new TableRenderer(3);
+        for (HistogramRecord rec : histogram.getHistogram()) {
+            table.printLine(rec.getClassname(), String.valueOf(rec.getNumberOf()), String.valueOf(rec.getTotalSize()));
+        }
+        table.render(out);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/locale/LocaleResources.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,81 @@
+/*
+ * 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.vm.heap.analysis.command.locale;
+
+import com.redhat.thermostat.common.locale.Translate;
+
+public enum LocaleResources {
+    HOST_SERVICE_UNAVAILABLE,
+    VM_SERVICE_UNAVAILABLE,
+    HEAP_SERVICE_UNAVAILABLE,
+    
+    HEADER_TIMESTAMP,
+    HEADER_HOST_ID,
+    HEADER_VM_ID,
+    HEADER_HEAP_ID,
+    HEADER_OBJECT_ID,
+    HEADER_OBJECT_TYPE,
+    
+    FILE_REQUIRED,
+    INVALID_LIMIT,
+    HEAP_ID_NOT_FOUND,
+    HEAP_ID_REQUIRED,
+    SEARCH_TERM_REQUIRED,
+    HEAP_DUMP_ERROR,
+    
+    COMMAND_HEAP_DUMP_DONE,
+
+    COMMAND_FIND_ROOT_NO_ROOT_FOUND,
+
+    COMMAND_OBJECT_INFO_OBJECT_ID,
+    COMMAND_OBJECT_INFO_TYPE,
+    COMMAND_OBJECT_INFO_SIZE,
+    COMMAND_OBJECT_INFO_HEAP_ALLOCATED,
+    COMMAND_OBJECT_INFO_REFERENCES,
+    COMMAND_OBJECT_INFO_REFERRERS,
+
+    COMMAND_SAVE_HEAP_DUMP_SAVED_TO_FILE,
+    COMMAND_SAVE_HEAP_DUMP_ERROR_SAVING,
+    COMMAND_SAVE_HEAP_DUMP_ERROR_CLOSING_STREAM,
+    ;
+    
+    static final String RESOURCE_BUNDLE = "com.redhat.thermostat.vm.heap.analysis.command.locale.strings";
+
+    public static Translate<LocaleResources> createLocalizer() {
+        return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/resources/META-INF/services/com.redhat.thermostat.common.cli.Command	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,7 @@
+com.redhat.thermostat.vm.heap.analysis.command.internal.DumpHeapCommand
+com.redhat.thermostat.vm.heap.analysis.command.internal.ListHeapDumpsCommand
+com.redhat.thermostat.vm.heap.analysis.command.internal.SaveHeapDumpToFileCommand
+com.redhat.thermostat.vm.heap.analysis.command.internal.ShowHeapHistogramCommand
+com.redhat.thermostat.vm.heap.analysis.command.internal.FindObjectsCommand
+com.redhat.thermostat.vm.heap.analysis.command.internal.ObjectInfoCommand
+com.redhat.thermostat.vm.heap.analysis.command.internal.FindRootCommand
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/resources/com/redhat/thermostat/vm/heap/analysis/command/locale/strings.properties	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,32 @@
+HOST_SERVICE_UNAVAILABLE = Unable to access host information (HostInfoDAO unavailable)
+VM_SERVICE_UNAVAILABLE = Unable to access vm information (VmInfoDAO unavailable)
+HEAP_SERVICE_UNAVAILABLE = Unable to access heap informatio (HeapDAO unavailable)
+
+HEADER_TIMESTAMP = TIMESTAMP
+HEADER_HOST_ID = HOST ID
+HEADER_VM_ID = VM ID
+HEADER_HEAP_ID = HEAP ID
+HEADER_OBJECT_ID = ID
+HEADER_OBJECT_TYPE = TYPE
+
+FILE_REQUIRED = A file name is required
+INVALID_LIMIT = Invalid limit {0}
+HEAP_ID_NOT_FOUND = Heap ID not found: {0}
+HEAP_ID_REQUIRED = Heap ID required
+SEARCH_TERM_REQUIRED = A search term is required
+HEAP_DUMP_ERROR = Error dumping heap (agent: {0}, vm: {1})
+
+COMMAND_HEAP_DUMP_DONE = Done
+
+COMMAND_FIND_ROOT_NO_ROOT_FOUND = No root found for: {0}
+
+COMMAND_OBJECT_INFO_OBJECT_ID = Object ID:
+COMMAND_OBJECT_INFO_TYPE = Type:
+COMMAND_OBJECT_INFO_SIZE = Size:
+COMMAND_OBJECT_INFO_HEAP_ALLOCATED = Heap allocated:
+COMMAND_OBJECT_INFO_REFERENCES = References:
+COMMAND_OBJECT_INFO_REFERRERS = Referrers:
+
+COMMAND_SAVE_HEAP_DUMP_SAVED_TO_FILE = Saved heap dump to {0}
+COMMAND_SAVE_HEAP_DUMP_ERROR_SAVING = error saving heap to file: {0}
+COMMAND_SAVE_HEAP_DUMP_ERROR_CLOSING_STREAM = error closing heap stream: {0}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ActivatorTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,85 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.redhat.thermostat.common.cli.Command;
+import com.redhat.thermostat.test.StubBundleContext;
+import com.redhat.thermostat.tools.cli.ShellCommand;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(FrameworkUtil.class)
+public class ActivatorTest {
+
+    @Test
+    public void testCommandsRegistered() throws Exception {
+        /*
+         * ServiceLoader pulls in all commands from bundles on the classpath.
+         * During maven builds the tools bundle is on the classpath which uses
+         * the no-arg constructor of ShellCommand. That in turn uses
+         * FrameworkUtil. We need to mock FrameworkUtil here in order to avoid
+         * that throwing NPEs.
+         */
+        PowerMockito.mockStatic(FrameworkUtil.class);
+        Bundle mockBundle = mock(Bundle.class);
+        when(FrameworkUtil.getBundle(ShellCommand.class)).thenReturn(mockBundle);
+        StubBundleContext ctx = new StubBundleContext();
+        when(mockBundle.getBundleContext()).thenReturn(ctx);
+        Activator activator = new Activator();
+        
+        activator.start(ctx);
+        
+        assertTrue(ctx.isServiceRegistered(Command.class.getName(), DumpHeapCommand.class));
+        assertTrue(ctx.isServiceRegistered(Command.class.getName(), FindObjectsCommand.class));
+        assertTrue(ctx.isServiceRegistered(Command.class.getName(), FindRootCommand.class));
+        assertTrue(ctx.isServiceRegistered(Command.class.getName(), ListHeapDumpsCommand.class));
+        assertTrue(ctx.isServiceRegistered(Command.class.getName(), ObjectInfoCommand.class));
+        assertTrue(ctx.isServiceRegistered(Command.class.getName(), SaveHeapDumpToFileCommand.class));
+        assertTrue(ctx.isServiceRegistered(Command.class.getName(), ShowHeapHistogramCommand.class));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/DumpHeapCommandTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,191 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import com.redhat.thermostat.common.cli.Command;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleArguments;
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.test.TestCommandContextFactory;
+import com.redhat.thermostat.vm.heap.analysis.command.locale.LocaleResources;
+
+public class DumpHeapCommandTest {
+
+    private static final Translate<LocaleResources> TRANSLATOR = LocaleResources
+            .createLocalizer();
+
+    @Test
+    public void testBasics() {
+        Command command = new DumpHeapCommand();
+        assertEquals("dump-heap", command.getName());
+        assertNotNull(command.getDescription());
+        assertNotNull(command.getUsage());
+    }
+
+    @Test
+    public void verifyAcuallyCallsWorker() throws CommandException {
+        AgentInfoDAO agentInfoDao = mock(AgentInfoDAO.class);
+        OSGIUtils osgi = mock(OSGIUtils.class);
+        when(osgi.getService(AgentInfoDAO.class)).thenReturn(agentInfoDao);
+
+        DumpHeapHelper impl = mock(DumpHeapHelper.class);
+        final ArgumentCaptor<Runnable> successHandler = ArgumentCaptor
+                .forClass(Runnable.class);
+        doAnswer(new Answer<Void>() {
+
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                successHandler.getValue().run();
+                return null;
+            }
+        }).when(impl).execute(eq(agentInfoDao), any(VmRef.class),
+                successHandler.capture(), any(Runnable.class));
+
+        DumpHeapCommand command = new DumpHeapCommand(osgi, impl);
+
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("hostId", "foo");
+        args.addArgument("vmId", "0");
+
+        command.run(factory.createContext(args));
+
+        verify(impl).execute(eq(agentInfoDao), isA(VmRef.class),
+                any(Runnable.class), any(Runnable.class));
+        assertEquals("Done\n", factory.getOutput());
+    }
+
+    @Test
+    public void verifyNeedsHostAndVmId() throws CommandException {
+        AgentInfoDAO agentInfoDao = mock(AgentInfoDAO.class);
+        OSGIUtils osgi = mock(OSGIUtils.class);
+        when(osgi.getService(AgentInfoDAO.class)).thenReturn(agentInfoDao);
+
+        DumpHeapHelper impl = mock(DumpHeapHelper.class);
+        DumpHeapCommand command = new DumpHeapCommand(osgi, impl);
+
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+
+        SimpleArguments args = new SimpleArguments();
+
+        try {
+            command.run(factory.createContext(args));
+            assertTrue("should not reach here", false);
+        } catch (CommandException ce) {
+            assertEquals("a hostId is required", ce.getMessage());
+        }
+    }
+
+    @Test
+    public void verifyFailsIfAgentDaoIsNotAvailable() {
+        OSGIUtils osgi = mock(OSGIUtils.class);
+
+        DumpHeapHelper impl = mock(DumpHeapHelper.class);
+        DumpHeapCommand command = new DumpHeapCommand(osgi, impl);
+
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("hostId", "foo");
+        args.addArgument("vmId", "0");
+
+        try {
+            command.run(factory.createContext(args));
+            assertTrue("should not reach here", false);
+        } catch (CommandException ce) {
+            assertEquals("Unable to access agent information", ce.getMessage());
+        }
+    }
+
+    @Test
+    public void verifyErrorMessage() {
+        final String HOST_ID = "myHost";
+        final int VM_ID = 9001;
+        AgentInfoDAO agentInfoDao = mock(AgentInfoDAO.class);
+        OSGIUtils osgi = mock(OSGIUtils.class);
+        when(osgi.getService(AgentInfoDAO.class)).thenReturn(agentInfoDao);
+
+        DumpHeapHelper impl = mock(DumpHeapHelper.class);
+        DumpHeapCommand command = new DumpHeapCommand(osgi, impl);
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("hostId", HOST_ID);
+        args.addArgument("vmId", String.valueOf(VM_ID));
+
+        doAnswer(new Answer<Object>() {
+
+            @Override
+            public Object answer(InvocationOnMock invocation) throws Throwable {
+                Runnable failRunnable = (Runnable) invocation.getArguments()[3];
+                failRunnable.run();
+                return null;
+            }
+        }).when(impl).execute(any(AgentInfoDAO.class), any(VmRef.class),
+                any(Runnable.class), any(Runnable.class));
+
+        try {
+            command.run(factory.createContext(args));
+            fail("CommandException expected");
+        } catch (CommandException e) {
+            assertEquals(TRANSLATOR.localize(LocaleResources.HEAP_DUMP_ERROR,
+                    HOST_ID, String.valueOf(VM_ID)), e.getMessage());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/DumpHeapHelperTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,160 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.net.InetSocketAddress;
+import java.util.Collection;
+
+import junit.framework.AssertionFailedError;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.client.command.RequestQueue;
+import com.redhat.thermostat.common.command.Request;
+import com.redhat.thermostat.common.command.Request.RequestType;
+import com.redhat.thermostat.common.command.RequestResponseListener;
+import com.redhat.thermostat.common.command.Response;
+import com.redhat.thermostat.common.command.Response.ResponseType;
+import com.redhat.thermostat.common.dao.AgentInfoDAO;
+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.storage.model.AgentInformation;
+import com.redhat.thermostat.vm.heap.analysis.command.internal.DumpHeapHelper;
+
+public class DumpHeapHelperTest {
+
+    private AgentInfoDAO agentInfoDao;
+    private DumpHeapHelper cmd;
+    private VmRef vmRef;
+    private RequestQueue reqQueue;
+    private Runnable heapDumpCompleteAction;
+    private Runnable heapDumpFailedAction;
+
+    @Before
+    public void setUp() {
+        reqQueue = mock(RequestQueue.class);
+        OSGIUtils osgiUtils = mock(OSGIUtils.class);
+        when(osgiUtils.getService(RequestQueue.class)).thenReturn(reqQueue);
+        OSGIUtils.setInstance(osgiUtils);
+
+        HostRef host = mock(HostRef.class);
+
+        AgentInformation agentInfo = mock(AgentInformation.class);
+        when(agentInfo.getConfigListenAddress()).thenReturn("test:123");
+
+        agentInfoDao = mock(AgentInfoDAO.class);
+        when(agentInfoDao.getAgentInformation(host)).thenReturn(agentInfo);
+
+        cmd = new DumpHeapHelper();
+        vmRef = mock(VmRef.class);
+        when(vmRef.getIdString()).thenReturn("123");
+        when(vmRef.getAgent()).thenReturn(host);
+        heapDumpCompleteAction = mock(Runnable.class);
+        heapDumpFailedAction = mock(Runnable.class);
+    }
+
+    @After
+    public void tearDown() {
+        heapDumpCompleteAction = null;
+        vmRef = null;
+        cmd = null;
+        reqQueue = null;
+    }
+
+    @Test
+    public void testExecute() {
+
+        cmd.execute(agentInfoDao, vmRef, heapDumpCompleteAction, heapDumpFailedAction);
+
+        ArgumentCaptor<Request> reqArg = ArgumentCaptor.forClass(Request.class);
+        verify(reqQueue).putRequest(reqArg.capture());
+        Request req = reqArg.getValue();
+        assertEquals("com.redhat.thermostat.vm.heap.analysis.agent.internal.HeapDumpReceiver", req.getReceiver());
+        verifyClassExists(req.getReceiver());
+        assertEquals(RequestType.RESPONSE_EXPECTED, req.getType());
+        assertEquals("123", req.getParameter("vmId"));
+        assertEquals(new InetSocketAddress("test", 123), req.getTarget());
+
+        Collection<RequestResponseListener> ls = req.getListeners();
+        for (RequestResponseListener l : ls) {
+            l.fireComplete(req, new Response(ResponseType.OK));
+        }
+        verify(heapDumpCompleteAction).run();
+        verify(heapDumpFailedAction, times(0)).run();
+    }
+
+    @Test
+    public void testExecuteFailure() {
+
+        cmd.execute(agentInfoDao, vmRef, heapDumpCompleteAction, heapDumpFailedAction);
+
+        ArgumentCaptor<Request> reqArg = ArgumentCaptor.forClass(Request.class);
+        verify(reqQueue).putRequest(reqArg.capture());
+        Request req = reqArg.getValue();
+        assertEquals("com.redhat.thermostat.vm.heap.analysis.agent.internal.HeapDumpReceiver", req.getReceiver());
+        verifyClassExists(req.getReceiver());
+        assertEquals(RequestType.RESPONSE_EXPECTED, req.getType());
+        assertEquals("123", req.getParameter("vmId"));
+        assertEquals(new InetSocketAddress("test", 123), req.getTarget());
+
+        Collection<RequestResponseListener> ls = req.getListeners();
+        for (RequestResponseListener l : ls) {
+            l.fireComplete(req, new Response(ResponseType.ERROR));
+        }
+        verify(heapDumpCompleteAction, times(0)).run();
+        verify(heapDumpFailedAction).run();
+    }
+
+    private void verifyClassExists(String receiver) {
+        try {
+            Class.forName(receiver);
+        } catch (ClassNotFoundException e) {
+            throw new AssertionFailedError();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/FindObjectsCommandTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,224 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleArguments;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.storage.model.HeapInfo;
+import com.redhat.thermostat.test.TestCommandContextFactory;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+import com.sun.tools.hat.internal.model.JavaClass;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+
+public class FindObjectsCommandTest {
+
+    private static final String HEAP_ID = "TEST_HEAP_ID";
+
+    private FindObjectsCommand cmd;
+
+    private HeapDump heapDump;
+
+    private HeapDAO dao;
+
+    @Before
+    public void setUp() {
+        setupHeapDump();
+
+        setupDAO();
+
+        OSGIUtils serviceProvider = mock(OSGIUtils.class);
+        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(dao);
+
+        cmd = new FindObjectsCommand(serviceProvider);
+
+    }
+
+    private void setupHeapDump() {
+        heapDump = mock(HeapDump.class);
+        JavaClass fooCls = mock(JavaClass.class);
+        when(fooCls.getName()).thenReturn("FooType");
+        JavaHeapObject fooObj = mock(JavaHeapObject.class);
+        when(fooObj.getIdString()).thenReturn("123");
+        when(fooObj.getClazz()).thenReturn(fooCls);
+        JavaClass barCls = mock(JavaClass.class);
+        when(barCls.getName()).thenReturn("BarType");
+        JavaHeapObject barObj = mock(JavaHeapObject.class);
+        when(barObj.getIdString()).thenReturn("456");
+        when(barObj.getClazz()).thenReturn(barCls);
+        JavaClass bazCls = mock(JavaClass.class);
+        when(bazCls.getName()).thenReturn("BazType");
+        JavaHeapObject bazObj = mock(JavaHeapObject.class);
+        when(bazObj.getIdString()).thenReturn("789");
+        when(bazObj.getClazz()).thenReturn(bazCls);
+
+        when(heapDump.searchObjects("fluff", 10)).thenReturn(Arrays.asList("foo", "bar", "baz"));
+        when(heapDump.searchObjects("fluff", 2)).thenReturn(Arrays.asList("foo", "bar"));
+        when(heapDump.findObject("foo")).thenReturn(fooObj);
+        when(heapDump.findObject("bar")).thenReturn(barObj);
+        when(heapDump.findObject("baz")).thenReturn(bazObj);
+    }
+
+    private void setupDAO() {
+        HeapInfo heapInfo = mock(HeapInfo.class);
+
+        dao = mock(HeapDAO.class);
+        when(dao.getHeapInfo(HEAP_ID)).thenReturn(heapInfo);
+        when(dao.getHeapDump(heapInfo)).thenReturn(heapDump);
+    }
+
+    @Test
+    public void testName() {
+        assertEquals("find-objects", cmd.getName());
+    }
+
+    @Test
+    public void testDescAndUsage() {
+        assertNotNull(cmd.getDescription());
+        assertNotNull(cmd.getUsage());
+    }
+
+    @Ignore
+    @Test
+    public void testOptions() {
+        Options options = cmd.getOptions();
+        assertEquals(2, options.getOptions().size());
+
+        assertTrue(options.hasOption("heapId"));
+        Option heapOption = options.getOption("heapId");
+        assertEquals("the ID of the heapdump to analyze", heapOption.getDescription());
+        assertTrue(heapOption.isRequired());
+        assertTrue(heapOption.hasArg());
+
+        assertTrue(options.hasOption("limit"));
+        Option limitOption = options.getOption("limit");
+        assertEquals("limit search to top N results, defaults to 10", limitOption.getDescription());
+        assertFalse(limitOption.isRequired());
+        assertTrue(limitOption.hasArg());
+    }
+
+    @Test
+    public void testStorageRequired() {
+        assertTrue(cmd.isStorageRequired());
+    }
+
+    @Test
+    public void testSimpleSearch() throws CommandException {
+
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("heapId", HEAP_ID);
+        args.addNonOptionArgument("fluff");
+
+        cmd.run(factory.createContext(args));
+
+        String expected = "ID  TYPE\n" +
+                          "123 FooType\n" +
+                          "456 BarType\n" +
+                          "789 BazType\n";
+
+        assertEquals(expected, factory.getOutput());
+
+    }
+
+    @Test
+    public void testSearchWithLimit() throws CommandException {
+
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("heapId", HEAP_ID);
+        args.addArgument("limit", "2");
+        args.addNonOptionArgument("fluff");
+
+        cmd.run(factory.createContext(args));
+
+        String expected = "ID  TYPE\n" +
+                          "123 FooType\n" +
+                          "456 BarType\n";
+
+        assertEquals(expected, factory.getOutput());
+
+    }
+
+    @Test(expected=CommandException.class)
+    public void testSearchWithInvalidLimit() throws CommandException {
+
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("heapId", HEAP_ID);
+        args.addArgument("limit", "urgs");
+        args.addNonOptionArgument("fluff");
+
+        cmd.run(factory.createContext(args));
+
+
+    }
+
+    @Test
+    public void testSearchWithBadHeapId() throws CommandException {
+        final String INVALID_HEAP_ID = "foobarbaz";
+
+        HeapDAO dao = mock(HeapDAO.class);
+        when(dao.getHeapInfo(INVALID_HEAP_ID)).thenReturn(null);
+        when(dao.getHeapDump(isA(HeapInfo.class))).thenReturn(null);
+
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("heapId", INVALID_HEAP_ID);
+
+        cmd.run(factory.createContext(args));
+
+        assertEquals("Heap ID not found: " + INVALID_HEAP_ID + "\n", factory.getOutput());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/FindRootCommandTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,342 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Collection;
+import java.util.Enumeration;
+
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.stubbing.OngoingStubbing;
+
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleArguments;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.storage.model.HeapInfo;
+import com.redhat.thermostat.test.TestCommandContextFactory;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+import com.sun.tools.hat.internal.model.JavaClass;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+import com.sun.tools.hat.internal.model.Root;
+import com.sun.tools.hat.internal.model.Snapshot;
+
+public class FindRootCommandTest {
+
+    private static final String HEAP_ID = "TEST_HEAP_ID";
+
+    private FindRootCommand cmd;
+
+    private JavaHeapObject fooObj;
+
+    private JavaHeapObject barObj;
+
+    private JavaHeapObject bazObj;
+
+    private JavaHeapObject bumObj;
+
+    private JavaHeapObject beeObj;
+
+    private HeapDAO dao;
+
+    @Before
+    public void setUp() {
+        HeapDump heapDump = setupHeapDump();
+        setupDAO(heapDump);
+
+        OSGIUtils serviceProvider = mock(OSGIUtils.class);
+        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(dao);
+
+        cmd = new FindRootCommand(serviceProvider);
+    }
+
+    @After
+    public void tearDown() {
+        fooObj = null;
+        barObj = null;
+        bazObj = null;
+        bumObj = null;
+        beeObj = null;
+        cmd = null;
+    }
+
+    @SuppressWarnings("rawtypes")
+    private HeapDump setupHeapDump() {
+        fooObj = createMockObject("FooType", "123");
+        barObj = createMockObject("BarType", "456");
+        bazObj = createMockObject("BazType", "789");
+        bumObj = createMockObject("BumType", "987");
+        beeObj = createMockObject("BeeType", "654");
+        // Setup referrer network.
+        Enumeration fooRefs = createReferrerEnum(barObj);
+        // The exception is thrown in circle-tests when we visit the foo object again.
+        when(fooObj.getReferers()).thenReturn(fooRefs).thenThrow(new RuntimeException());
+        Enumeration barRefs = createReferrerEnum(bazObj, bumObj);
+        when(barObj.getReferers()).thenReturn(barRefs);
+        Enumeration bumRefs = createReferrerEnum(beeObj);
+        when(bumObj.getReferers()).thenReturn(bumRefs);
+        Enumeration emptyRefs = createReferrerEnum();
+        when(bazObj.getReferers()).thenReturn(emptyRefs);
+        when(beeObj.getReferers()).thenReturn(emptyRefs);
+
+        // Setup referrer descriptions.
+        when(barObj.describeReferenceTo(same(fooObj), any(Snapshot.class))).thenReturn("field foo");
+        when(bazObj.describeReferenceTo(same(barObj), any(Snapshot.class))).thenReturn("field bar");
+        when(bumObj.describeReferenceTo(same(barObj), any(Snapshot.class))).thenReturn("field bar");
+        when(beeObj.describeReferenceTo(same(bumObj), any(Snapshot.class))).thenReturn("field bum");
+
+        // Setup roots.
+        Root bazRoot = mock(Root.class);
+        when(bazRoot.getDescription()).thenReturn("baz root");
+        when(bazObj.getRoot()).thenReturn(bazRoot);
+        Root beeRoot = mock(Root.class);
+        when(beeRoot.getDescription()).thenReturn("bee root");
+        when(beeObj.getRoot()).thenReturn(beeRoot);
+
+        // Setup heap dump.
+        HeapDump heapDump = mock(HeapDump.class);
+        when(heapDump.findObject("foo")).thenReturn(fooObj);
+        return heapDump;
+    }
+
+    private void setupDAO(HeapDump heapDump) {
+
+        HeapInfo heapInfo = mock(HeapInfo.class);
+
+        dao = mock(HeapDAO.class);
+        when(dao.getHeapInfo(HEAP_ID)).thenReturn(heapInfo);
+        when(dao.getHeapDump(heapInfo)).thenReturn(heapDump);
+
+    }
+
+    private JavaHeapObject createMockObject(String className, String id) {
+        JavaClass cls = mock(JavaClass.class);
+        when(cls.getName()).thenReturn(className);
+        JavaHeapObject obj = mock(JavaHeapObject.class);
+        when(obj.getIdString()).thenReturn(id);
+        when(obj.getClazz()).thenReturn(cls);
+        return obj;
+    }
+
+    @SuppressWarnings("rawtypes")
+    private Enumeration createReferrerEnum(JavaHeapObject... objs) {
+        Enumeration refs = mock(Enumeration.class);
+        OngoingStubbing<Boolean> hasMoreElements = when(refs.hasMoreElements());
+        for (int i = 0; i < objs.length; i++) {
+            hasMoreElements = hasMoreElements.thenReturn(true);
+        }
+        hasMoreElements.thenReturn(false);
+        OngoingStubbing<Object> nextElement = when(refs.nextElement());
+        for (JavaHeapObject obj : objs) {
+            nextElement = nextElement.thenReturn(obj);
+        }
+        nextElement.thenReturn(null);
+        return refs;
+    }
+
+    @Test
+    public void testName() {
+        assertEquals("find-root", cmd.getName());
+    }
+
+    @Test
+    public void testDescAndUsage() {
+        assertNotNull(cmd.getDescription());
+        assertNotNull(cmd.getUsage());
+    }
+
+    @Ignore
+    @Test
+    public void testOptions() {
+        String heapIdOption = "heapId";
+        String objectIdOption = "objectId";
+        String allOption = "all";
+        Options options = cmd.getOptions();
+        @SuppressWarnings("unchecked")
+        Collection<Options> theOptions = options.getOptions();
+        assertEquals(3, theOptions.size());
+
+        assertTrue(options.hasOption(heapIdOption));
+        Option heapOption = options.getOption(heapIdOption);
+        assertEquals("the ID of the heapdump to analyze", heapOption.getDescription());
+        assertTrue(heapOption.isRequired());
+        assertTrue(heapOption.hasArg());
+
+        assertTrue(options.hasOption(objectIdOption));
+        Option objectOption = options.getOption(objectIdOption);
+        assertEquals("the ID of the object to query", objectOption.getDescription());
+        assertTrue(heapOption.isRequired());
+        assertTrue(heapOption.hasArg());
+
+        assertTrue(options.hasOption(allOption));
+        Option all = options.getOption(allOption);
+        assertEquals("finds all paths to GC roots", all.getDescription());
+        assertFalse(all.isRequired());
+        assertFalse(all.hasArg());
+    }
+
+    @Test
+    public void testStorageRequired() {
+        assertTrue(cmd.isStorageRequired());
+    }
+
+    @Test
+    public void testSimpleAllRootsSearch() throws CommandException {
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("heapId", HEAP_ID);
+        args.addArgument("objectId", "foo");
+        args.addArgument("all", "true");
+
+        cmd.run(factory.createContext(args));
+
+        String expected = "baz root -> BazType@789\n" +
+                          "\u2514field bar in BazType@789 -> BarType@456\n" +
+                          " \u2514field foo in BarType@456 -> FooType@123\n" +
+                          "\n" +
+                          "bee root -> BeeType@654\n" +
+                          "\u2514field bum in BeeType@654 -> BumType@987\n" +
+                          " \u2514field bar in BumType@987 -> BarType@456\n" +
+                          "  \u2514field foo in BarType@456 -> FooType@123\n" +
+                          "\n";
+
+        assertEquals(expected, factory.getOutput());
+
+    }
+
+    @Test
+    public void testSimpleRootSearch() throws CommandException {
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("heapId", HEAP_ID);
+        args.addArgument("objectId", "foo");
+
+        cmd.run(factory.createContext(args));
+
+        String expected = "baz root -> BazType@789\n" +
+                          "\u2514field bar in BazType@789 -> BarType@456\n" +
+                          " \u2514field foo in BarType@456 -> FooType@123\n" +
+                          "\n";
+
+        assertEquals(expected, factory.getOutput());
+
+    }
+
+    @Test
+    public void testSearchWithoutRoot() throws CommandException {
+        when(bazObj.getRoot()).thenReturn(null);
+        when(beeObj.getRoot()).thenReturn(null);
+
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("heapId", HEAP_ID);
+        args.addArgument("objectId", "foo");
+
+        cmd.run(factory.createContext(args));
+
+        String expected = "No root found for: FooType@123\n";
+
+        assertEquals(expected, factory.getOutput());
+
+    }
+
+    @Test
+    public void testSearchWithoutRootWithCircle() throws CommandException {
+        when(bazObj.getRoot()).thenReturn(null);
+        @SuppressWarnings("rawtypes")
+        Enumeration bazReferrers = createReferrerEnum(fooObj);
+        when(bazObj.getReferers()).thenReturn(bazReferrers);
+        when(beeObj.getRoot()).thenReturn(null);
+        @SuppressWarnings("rawtypes")
+        Enumeration beeReferrers = createReferrerEnum(fooObj);
+        when(beeObj.getReferers()).thenReturn(beeReferrers);
+
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("heapId", HEAP_ID);
+        args.addArgument("objectId", "foo");
+
+        cmd.run(factory.createContext(args));
+
+        String expected = "No root found for: FooType@123\n";
+
+        assertEquals(expected, factory.getOutput());
+
+    }
+
+    public void testHeapNotFound() throws CommandException {
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("heapId", "fluff");
+        args.addArgument("objectId", "foo");
+
+        try {
+            cmd.run(factory.createContext(args));
+            fail();
+        } catch (HeapNotFoundException ex) {
+           assertEquals("Heap ID not found: fluff", ex.getMessage());
+        }
+    }
+
+    public void testObjectNotFound() throws CommandException {
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("heapId", HEAP_ID);
+        args.addArgument("objectId", "fluff");
+
+        try {
+            cmd.run(factory.createContext(args));
+            fail();
+        } catch (ObjectNotFoundException ex) {
+            assertEquals("Object not found: fluff", ex.getMessage());
+         }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ListHeapDumpsCommandTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,265 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.TimeZone;
+
+import org.apache.commons.cli.Options;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.cli.Command;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleArguments;
+import com.redhat.thermostat.common.dao.HostInfoDAO;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.storage.model.HeapInfo;
+import com.redhat.thermostat.test.TestCommandContextFactory;
+import com.redhat.thermostat.vm.heap.analysis.command.internal.ListHeapDumpsCommand;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+
+public class ListHeapDumpsCommandTest {
+
+    private static TimeZone defaultTimezone;
+
+    @BeforeClass
+    public static void setUpClass() {
+        defaultTimezone = TimeZone.getDefault();
+        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
+    }
+
+    @AfterClass
+    public static void tearDownClass() {
+        TimeZone.setDefault(defaultTimezone);
+    }
+
+    @Test
+    public void verifyBasics() {
+        Command command = new ListHeapDumpsCommand();
+        assertEquals("list-heap-dumps", command.getName());
+        assertNotNull(command.getDescription());
+        assertNotNull(command.getUsage());
+    }
+
+    @Ignore
+    @Test
+    public void verifyOptions() {
+        Command command = new ListHeapDumpsCommand();
+        Options options = command.getOptions();
+        assertNotNull(options);
+        assertEquals(2, options.getOptions().size());
+    }
+
+    @Test
+    public void verifyFailsWithoutHostDao() throws Exception {
+        OSGIUtils serviceProvider = mock(OSGIUtils.class);
+
+        Command command = new ListHeapDumpsCommand(serviceProvider);
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+        try {
+            command.run(factory.createContext(new SimpleArguments()));
+        } catch (CommandException hostDaoNotAvailableException) {
+            assertEquals("Unable to access host information (HostInfoDAO unavailable)",
+                    hostDaoNotAvailableException.getMessage());
+        }
+    }
+
+    @Test
+    public void verifyWorksWithoutAnyInformation() throws CommandException {
+        HostInfoDAO hostInfo = mock(HostInfoDAO.class);
+        VmInfoDAO vmInfo = mock(VmInfoDAO.class);
+        HeapDAO heapDao = mock(HeapDAO.class);
+
+        OSGIUtils serviceProvider = mock(OSGIUtils.class);
+        when(serviceProvider.getServiceAllowNull(HostInfoDAO.class)).thenReturn(hostInfo);
+        when(serviceProvider.getServiceAllowNull(VmInfoDAO.class)).thenReturn(vmInfo);
+        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(heapDao);
+
+        Command command = new ListHeapDumpsCommand(serviceProvider);
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+        command.run(factory.createContext(new SimpleArguments()));
+        assertEquals("HOST ID VM ID HEAP ID TIMESTAMP\n", factory.getOutput());
+    }
+
+    @Test
+    public void verifyWorks() throws CommandException {
+        HostRef hostRef = mock(HostRef.class);
+        when(hostRef.getStringID()).thenReturn("host-id");
+        VmRef vmRef = mock(VmRef.class);
+        when(vmRef.getStringID()).thenReturn("1");
+
+        HeapInfo heapInfo = mock(HeapInfo.class);
+        Calendar timestamp = Calendar.getInstance();
+        timestamp.set(2012, 5, 7, 15, 32, 0);
+        when(heapInfo.getTimeStamp()).thenReturn(timestamp.getTimeInMillis());
+        when(heapInfo.getHeapId()).thenReturn("0001");
+
+        HeapDAO heapDao = mock(HeapDAO.class);
+
+        VmInfoDAO vmInfo = mock(VmInfoDAO.class);
+        when(vmInfo.getVMs(hostRef)).thenReturn(Arrays.asList(vmRef));
+
+        HostInfoDAO hostInfo = mock(HostInfoDAO.class);
+        when(hostInfo.getHosts()).thenReturn(Arrays.asList(hostRef));
+
+        when(heapDao.getAllHeapInfo(vmRef)).thenReturn(Arrays.asList(heapInfo));
+
+        OSGIUtils serviceProvider = mock(OSGIUtils.class);
+        when(serviceProvider.getServiceAllowNull(HostInfoDAO.class)).thenReturn(hostInfo);
+        when(serviceProvider.getServiceAllowNull(VmInfoDAO.class)).thenReturn(vmInfo);
+        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(heapDao);
+
+        Command command = new ListHeapDumpsCommand(serviceProvider);
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+        command.run(factory.createContext(new SimpleArguments()));
+
+        String expected = "HOST ID VM ID HEAP ID TIMESTAMP\n" +
+                          "host-id 1     0001    Thu Jun 07 15:32:00 UTC 2012\n";
+
+        assertEquals(expected, factory.getOutput());
+    }
+
+    @Test
+    public void verifyWorksWithFilterOnHost() throws CommandException {
+        HostRef hostRef1 = mock(HostRef.class);
+        when(hostRef1.getStringID()).thenReturn("host1");
+        VmRef vmRef1 = mock(VmRef.class);
+        when(vmRef1.getStringID()).thenReturn("1");
+
+        HostRef hostRef2 = mock(HostRef.class);
+        when(hostRef2.getStringID()).thenReturn("host2");
+        VmRef vmRef2 = mock(VmRef.class);
+        when(vmRef2.getStringID()).thenReturn("2");
+
+        HeapInfo heapInfo = mock(HeapInfo.class);
+        Calendar timestamp = Calendar.getInstance();
+        timestamp.set(2012, 5, 7, 15, 32, 0);
+        when(heapInfo.getTimeStamp()).thenReturn(timestamp.getTimeInMillis());
+        when(heapInfo.getHeapId()).thenReturn("0001");
+
+        HeapDAO heapDao = mock(HeapDAO.class);
+
+        VmInfoDAO vmInfo = mock(VmInfoDAO.class);
+        when(vmInfo.getVMs(isA(HostRef.class))).thenReturn(Arrays.asList(vmRef1)).thenReturn(Arrays.asList(vmRef2));
+
+        HostInfoDAO hostInfo = mock(HostInfoDAO.class);
+        when(hostInfo.getHosts()).thenReturn(Arrays.asList(hostRef1, hostRef2));
+
+        when(heapDao.getAllHeapInfo(vmRef1)).thenReturn(Arrays.asList(heapInfo));
+        when(heapDao.getAllHeapInfo(vmRef2)).thenReturn(Arrays.asList(heapInfo));
+
+        OSGIUtils serviceProvider = mock(OSGIUtils.class);
+        when(serviceProvider.getServiceAllowNull(HostInfoDAO.class)).thenReturn(hostInfo);
+        when(serviceProvider.getServiceAllowNull(VmInfoDAO.class)).thenReturn(vmInfo);
+        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(heapDao);
+
+        Command command = new ListHeapDumpsCommand(serviceProvider);
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("hostId", "host1");
+
+        command.run(factory.createContext(args));
+
+        String expected = "HOST ID VM ID HEAP ID TIMESTAMP\n" +
+                          "host1   1     0001    Thu Jun 07 15:32:00 UTC 2012\n";
+
+        assertEquals(expected, factory.getOutput());
+    }
+
+    @Test
+    public void verifyWorksWithFilterOnHostAndVM() throws CommandException {
+        HostRef hostRef1 = mock(HostRef.class);
+        when(hostRef1.getStringID()).thenReturn("host1");
+        when(hostRef1.getAgentId()).thenReturn("host1");
+        VmRef vmRef1 = mock(VmRef.class);
+        when(vmRef1.getStringID()).thenReturn("1");
+
+        HostRef hostRef2 = mock(HostRef.class);
+        when(hostRef2.getStringID()).thenReturn("host2");
+        VmRef vmRef2 = mock(VmRef.class);
+        when(vmRef2.getStringID()).thenReturn("2");
+
+        HeapInfo heapInfo = mock(HeapInfo.class);
+        Calendar timestamp = Calendar.getInstance();
+        timestamp.set(2012, 5, 7, 15, 32, 0);
+        when(heapInfo.getTimeStamp()).thenReturn(timestamp.getTimeInMillis());
+        when(heapInfo.getHeapDumpId()).thenReturn("0001");
+
+        HeapDAO heapDao = mock(HeapDAO.class);
+
+        VmInfoDAO vmInfo = mock(VmInfoDAO.class);
+        when(vmInfo.getVMs(isA(HostRef.class))).thenReturn(Arrays.asList(vmRef1)).thenReturn(Arrays.asList(vmRef2));
+
+        HostInfoDAO hostInfo = mock(HostInfoDAO.class);
+        when(hostInfo.getHosts()).thenReturn(Arrays.asList(hostRef1, hostRef2));
+
+        when(heapDao.getAllHeapInfo(vmRef1)).thenReturn(Arrays.asList(heapInfo));
+        when(heapDao.getAllHeapInfo(vmRef2)).thenReturn(Arrays.asList(heapInfo));
+
+        OSGIUtils serviceProvider = mock(OSGIUtils.class);
+        when(serviceProvider.getServiceAllowNull(HostInfoDAO.class)).thenReturn(hostInfo);
+        when(serviceProvider.getServiceAllowNull(VmInfoDAO.class)).thenReturn(vmInfo);
+        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(heapDao);
+
+        Command command = new ListHeapDumpsCommand(serviceProvider);
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("hostId", "host1");
+        args.addArgument("vmId", "1"); // vm id must be an int for the arg parser to work
+
+        command.run(factory.createContext(args));
+
+        String expected = "HOST ID VM ID HEAP ID TIMESTAMP\n";
+
+        assertEquals(expected, factory.getOutput());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ObjectInfoCommandTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,237 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Enumeration;
+
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleArguments;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.storage.model.HeapInfo;
+import com.redhat.thermostat.test.TestCommandContextFactory;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+import com.sun.tools.hat.internal.model.JavaClass;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+import com.sun.tools.hat.internal.model.JavaHeapObjectVisitor;
+import com.sun.tools.hat.internal.model.Snapshot;
+
+public class ObjectInfoCommandTest {
+
+    private static final String HEAP_ID = "TEST_HEAP_ID";
+
+    private ObjectInfoCommand cmd;
+    private HeapDump heapDump;
+
+    private HeapDAO dao;
+
+    @Before
+    public void setUp() {
+        setupHeapDump();
+        setupDAO();
+
+        OSGIUtils serviceProvider = mock(OSGIUtils.class);
+        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(dao);
+
+        cmd = new ObjectInfoCommand(serviceProvider);
+    }
+
+    @After
+    public void tearDown() {
+        heapDump = null;
+        cmd = null;
+    }
+
+    private void setupHeapDump() {
+        heapDump = mock(HeapDump.class);
+        JavaClass barCls = mock(JavaClass.class);
+        when(barCls.getName()).thenReturn("BarType");
+        final JavaHeapObject barObj = mock(JavaHeapObject.class);
+        when(barObj.getIdString()).thenReturn("456");
+        when(barObj.getClazz()).thenReturn(barCls);
+        JavaClass bazCls = mock(JavaClass.class);
+        when(bazCls.getName()).thenReturn("BazType");
+        final JavaHeapObject bazObj = mock(JavaHeapObject.class);
+        when(bazObj.getIdString()).thenReturn("789");
+        when(bazObj.getClazz()).thenReturn(bazCls);
+
+        JavaClass fooCls = mock(JavaClass.class);
+        when(fooCls.getName()).thenReturn("FooType");
+        JavaHeapObject fooObj = mock(JavaHeapObject.class);
+        when(fooObj.getIdString()).thenReturn("123");
+        when(fooObj.getClazz()).thenReturn(fooCls);
+        doAnswer(new Answer<Void>() {
+
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                JavaHeapObjectVisitor v = (JavaHeapObjectVisitor) invocation.getArguments()[0];
+                v.visit(barObj);
+                v.visit(bazObj);
+                return null;
+            }
+            
+        }).when(fooObj).visitReferencedObjects(any(JavaHeapObjectVisitor.class));
+        when(fooObj.describeReferenceTo(same(barObj), any(Snapshot.class))).thenReturn("field bar");
+        when(fooObj.describeReferenceTo(same(bazObj), any(Snapshot.class))).thenReturn("field baz");
+        @SuppressWarnings("rawtypes")
+        Enumeration referrerEnum = mock(Enumeration.class);
+        when(referrerEnum.hasMoreElements()).thenReturn(true).thenReturn(true).thenReturn(false);
+        when(referrerEnum.nextElement()).thenReturn(barObj).thenReturn(bazObj);
+        when(fooObj.getReferers()).thenReturn(referrerEnum);
+        when(barObj.describeReferenceTo(same(fooObj), any(Snapshot.class))).thenReturn("field foo");
+        when(bazObj.describeReferenceTo(same(fooObj), any(Snapshot.class))).thenReturn("field foo");
+        when(fooObj.isNew()).thenReturn(true);
+        when(fooObj.isHeapAllocated()).thenReturn(false);
+        when(fooObj.getSize()).thenReturn(128);
+        when(heapDump.findObject("foo")).thenReturn(fooObj);
+    }
+
+    private void setupDAO() {
+
+        HeapInfo heapInfo = mock(HeapInfo.class);
+
+        dao = mock(HeapDAO.class);
+        when(dao.getHeapInfo(HEAP_ID)).thenReturn(heapInfo);
+        when(dao.getHeapDump(heapInfo)).thenReturn(heapDump);
+    }
+
+    @Test
+    public void testName() {
+        assertEquals("object-info", cmd.getName());
+    }
+
+    @Test
+    public void testDescAndUsage() {
+        assertNotNull(cmd.getDescription());
+        assertNotNull(cmd.getUsage());
+    }
+
+    @Ignore
+    @Test
+    public void testOptions() {
+        Options options = cmd.getOptions();
+        assertEquals(2, options.getOptions().size());
+
+        assertTrue(options.hasOption("heapId"));
+        Option heapOption = options.getOption("heapId");
+        assertEquals("the ID of the heapdump to analyze", heapOption.getDescription());
+        assertTrue(heapOption.isRequired());
+        assertTrue(heapOption.hasArg());
+
+        assertTrue(options.hasOption("objectId"));
+        Option objOption = options.getOption("objectId");
+        assertEquals("the ID of the object to query", objOption.getDescription());
+        assertTrue(objOption.isRequired());
+        assertTrue(objOption.hasArg());
+    }
+
+    @Test
+    public void testStorageRequired() {
+        assertTrue(cmd.isStorageRequired());
+    }
+
+    @Test
+    public void testSimpleObject() throws CommandException {
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("heapId", HEAP_ID);
+        args.addArgument("objectId", "foo");
+
+        cmd.run(factory.createContext(args));
+
+        String expected = "Object ID:      123\n" +
+                          "Type:           FooType\n" +
+                          "Size:           128 bytes\n" +
+                          "Heap allocated: false\n" +
+                          "References:     \n" +
+                          "                [field bar] -> BarType@456\n" +
+                          "                [field baz] -> BazType@789\n" +
+                          "Referrers:      \n" +
+                          "                BarType@456 -> [field foo]\n" +
+                          "                BazType@789 -> [field foo]\n";
+
+        assertEquals(expected, factory.getOutput());
+
+    }
+
+    public void testHeapNotFound() throws CommandException {
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("heapId", "fluff");
+        args.addArgument("objectId", "foo");
+
+        try {
+            cmd.run(factory.createContext(args));
+            fail();
+        } catch (HeapNotFoundException ex) {
+            assertEquals("Heap ID not found: fluff", ex.getMessage());
+        }
+    }
+
+    public void testObjectNotFound() throws CommandException {
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("heapId", HEAP_ID);
+        args.addArgument("objectId", "fluff");
+
+        try {
+            cmd.run(factory.createContext(args));
+            fail();
+        } catch (ObjectNotFoundException ex) {
+            assertEquals("Object not found: fluff", ex.getMessage());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/SaveHeapDumpToFileCommandTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,137 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.nio.charset.Charset;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.common.cli.Command;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleArguments;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.storage.model.HeapInfo;
+import com.redhat.thermostat.test.TestCommandContextFactory;
+import com.redhat.thermostat.vm.heap.analysis.command.internal.SaveHeapDumpToFileCommand;
+import com.redhat.thermostat.vm.heap.analysis.command.internal.SaveHeapDumpToFileCommand.FileStreamCreator;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+
+public class SaveHeapDumpToFileCommandTest {
+
+    @Test
+    public void verifyBasicInformation() {
+        Command command = new SaveHeapDumpToFileCommand();
+        assertEquals("save-heap-dump-to-file", command.getName());
+        assertNotNull(command.getDescription());
+        assertNotNull(command.getUsage());
+    }
+
+    @Test (expected=CommandException.class)
+    public void verifyMissingHeapIdThrowsException() throws CommandException {
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("hostId", "host-id");
+        args.addArgument("vmId", "1");
+        args.addArgument("file", "heap-id-1");
+
+        OSGIUtils serviceProvider = mock(OSGIUtils.class);
+        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(mock(HeapDAO.class));
+
+        Command command = new SaveHeapDumpToFileCommand(serviceProvider, mock(FileStreamCreator.class));
+        command.run(factory.createContext(args));
+    }
+
+    @Test (expected=CommandException.class)
+    public void verifyMissingFileNameThrowsException() throws CommandException {
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("hostId", "host-id");
+        args.addArgument("vmId", "1");
+        args.addArgument("heapId", "heap-id-1");
+
+        OSGIUtils serviceProvider = mock(OSGIUtils.class);
+        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(mock(HeapDAO.class));
+
+        Command command = new SaveHeapDumpToFileCommand(serviceProvider, mock(FileStreamCreator.class));
+        command.run(factory.createContext(args));
+    }
+
+    @Test
+    public void verifyCommandWorks() throws CommandException, FileNotFoundException {
+        final String HEAP_ID = "heap-id-1";
+        final String FILE_NAME = "some-file-name";
+        final String HEAP_CONTENTS = "0xCAFEBABE";
+        final byte[] HEAP_CONTENT_BYTES = HEAP_CONTENTS.getBytes(Charset.forName("UTF-8"));
+
+        ByteArrayOutputStream heapDumpStream = new ByteArrayOutputStream();
+
+        HeapDAO heapDao = mock(HeapDAO.class);
+
+        HeapInfo info = mock(HeapInfo.class);
+        when(heapDao.getHeapInfo(HEAP_ID)).thenReturn(info);
+        when(heapDao.getHeapDumpData(info)).thenReturn(new ByteArrayInputStream(HEAP_CONTENT_BYTES));
+
+        OSGIUtils serviceProvider = mock(OSGIUtils.class);
+        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(heapDao);
+
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("heapId", HEAP_ID);
+        args.addArgument("file", FILE_NAME);
+
+        FileStreamCreator creator = mock(FileStreamCreator.class);
+        when(creator.createOutputStream(FILE_NAME)).thenReturn(heapDumpStream);
+
+        Command command = new SaveHeapDumpToFileCommand(serviceProvider, creator);
+        command.run(factory.createContext(args));
+
+        assertArrayEquals(HEAP_CONTENT_BYTES, heapDumpStream.toByteArray());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ShowHeapHistogramCommandTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,139 @@
+/*
+ * 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.vm.heap.analysis.command.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.common.cli.Command;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.SimpleArguments;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.storage.model.HeapInfo;
+import com.redhat.thermostat.test.TestCommandContextFactory;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram;
+import com.sun.tools.hat.internal.model.JavaClass;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+
+public class ShowHeapHistogramCommandTest {
+
+    @Test
+    public void verifyBasics() {
+        Command command = new ShowHeapHistogramCommand();
+
+        assertEquals("show-heap-histogram", command.getName());
+        assertNotNull(command.getDescription());
+        assertNotNull(command.getUsage());
+    }
+
+    @Test
+    public void verifyWorks() throws CommandException {
+        ObjectHistogram histo = new ObjectHistogram();
+
+        JavaClass cls1 = mock(JavaClass.class);
+        JavaHeapObject obj1 = mock(JavaHeapObject.class);
+        when(cls1.getName()).thenReturn("class1");
+        when(obj1.getClazz()).thenReturn(cls1);
+        when(obj1.getSize()).thenReturn(5);
+        JavaHeapObject obj2 = mock(JavaHeapObject.class);
+        when(obj2.getClazz()).thenReturn(cls1);
+        when(obj2.getSize()).thenReturn(3);
+        JavaClass cls2 = mock(JavaClass.class);
+        JavaHeapObject obj3 = mock(JavaHeapObject.class);
+        when(cls2.getName()).thenReturn("verylongclassnameclass2");
+        when(obj3.getClazz()).thenReturn(cls2);
+        when(obj3.getSize()).thenReturn(10);
+
+        histo.addThing(obj1);
+        histo.addThing(obj2);
+        histo.addThing(obj3);
+
+        final String HEAP_ID = "heap-id-1";
+
+        HeapDAO heapDao = mock(HeapDAO.class);
+
+        HeapInfo heapInfo = mock(HeapInfo.class);
+        when(heapDao.getHeapInfo(HEAP_ID)).thenReturn(heapInfo);
+        when(heapDao.getHistogram(heapInfo)).thenReturn(histo);
+
+        OSGIUtils serviceProvider = mock(OSGIUtils.class);
+        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(heapDao);
+
+        Command command = new ShowHeapHistogramCommand(serviceProvider);
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("heapId", HEAP_ID);
+
+        command.run(factory.createContext(args));
+
+        assertEquals("class1                  2 8\n" +
+                     "verylongclassnameclass2 1 10\n", factory.getOutput());
+        verify(serviceProvider).ungetService(HeapDAO.class, heapDao);
+    }
+
+    @Test
+    public void verifyWorkWithBadHeapId() throws CommandException {
+        final String BAD_HEAP_ID = "invalid-heap-id";
+
+        HeapDAO heapDao = mock(HeapDAO.class);
+
+        when(heapDao.getHeapInfo(BAD_HEAP_ID)).thenReturn(null);
+        when(heapDao.getHistogram(any(HeapInfo.class))).thenReturn(null);
+
+        OSGIUtils serviceProvider = mock(OSGIUtils.class);
+        when(serviceProvider.getServiceAllowNull(HeapDAO.class)).thenReturn(heapDao);
+
+        Command command = new ShowHeapHistogramCommand(serviceProvider);
+        TestCommandContextFactory factory = new TestCommandContextFactory();
+
+        SimpleArguments args = new SimpleArguments();
+        args.addArgument("heapId", BAD_HEAP_ID);
+
+        command.run(factory.createContext(args));
+
+        assertEquals("Heap ID not found: " + BAD_HEAP_ID + "\n", factory.getOutput());
+        verify(serviceProvider).ungetService(HeapDAO.class, heapDao);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/locale/LocaleResourcesTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,54 @@
+/*
+ * 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.vm.heap.analysis.command.locale;
+
+import com.redhat.thermostat.test.locale.AbstractLocaleResourcesTest;
+
+public class LocaleResourcesTest extends AbstractLocaleResourcesTest<LocaleResources> {
+
+    @Override
+    protected Class<LocaleResources> getEnumClass() {
+        return LocaleResources.class;
+    }
+
+    @Override
+    protected String getResourceBundle() {
+        return LocaleResources.RESOURCE_BUNDLE;
+    }
+
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/common/pom.xml	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,111 @@
+<?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>
+    <artifactId>thermostat-vm-heap-analysis</artifactId>
+    <groupId>com.redhat.thermostat</groupId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>thermostat-vm-heap-analysis-common</artifactId>
+  <packaging>bundle</packaging>
+  <name>Thermostat VM Heap Analysis Common plugin</name>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-SymbolicName>com.redhat.thermostat.vm.heap.analysis.common</Bundle-SymbolicName>
+            <Export-Package>
+               com.redhat.thermostat.vm.heap.analysis.common
+            </Export-Package>
+            <Private-Package>
+               com.redhat.thermostat.vm.heap.analysis.common.internal
+            </Private-Package>
+            <Bundle-Activator>com.redhat.thermostat.vm.heap.analysis.common.internal.Activator</Bundle-Activator>
+            <!-- Do not autogenerate uses clauses in Manifests -->
+            <_nouses>true</_nouses>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-mockito</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/HeapDAO.java	Wed Dec 12 15:52:00 2012 -0500
@@ -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.vm.heap.analysis.common;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.storage.core.Category;
+import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.model.HeapInfo;
+
+public interface HeapDAO {
+
+    static final Key<String> heapIdKey = new Key<String>("heapId", false);
+    static final Key<String> heapDumpIdKey = new Key<String>("heapDumpId", false);
+    static final Key<String> histogramIdKey = new Key<String>("histogramId", false);
+
+    public static final Category heapInfoCategory = new Category("vm-heap-info", Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, heapIdKey, heapDumpIdKey, histogramIdKey);
+
+    void putHeapInfo(HeapInfo heapInfo, File heapDumpFile, ObjectHistogram histogramData) throws IOException;
+
+    Collection<HeapInfo> getAllHeapInfo(VmRef vm);
+
+    InputStream getHeapDumpData(HeapInfo heapInfo);
+
+    ObjectHistogram getHistogram(HeapInfo heapInfo);
+
+    HeapInfo getHeapInfo(String heapId);
+
+    HeapDump getHeapDump(HeapInfo heapInfo);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/HeapDump.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,231 @@
+/*
+ * 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.vm.heap.analysis.common;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.Files;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.lucene.analysis.SimpleAnalyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.CorruptIndexException;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.search.WildcardQuery;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.LockObtainFailedException;
+import org.apache.lucene.store.RAMDirectory;
+import org.apache.lucene.util.Version;
+
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.model.HeapInfo;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+import com.sun.tools.hat.internal.model.Snapshot;
+import com.sun.tools.hat.internal.parser.Reader;
+
+/**
+ * NOTE: This class is thread-safe with respect to loading the heapdump and creating the index.
+ */
+public class HeapDump {
+
+    private static final String INDEX_FIELD_OBJECT_ID = "objectId";
+
+    private static final String INDEX_FIELD_CLASSNAME = "classname";
+
+    private static final Logger log = LoggingUtils.getLogger(HeapDump.class);
+
+    private final HeapInfo heapInfo;
+
+    private final HeapDAO heapDAO;
+
+    private Snapshot snapshot;
+
+    private Directory luceneIndex;
+
+    public HeapDump(HeapInfo heapInfo, HeapDAO heapDAO) {
+        this.heapInfo = heapInfo;
+        this.heapDAO = heapDAO;
+    }
+
+    public long getTimestamp() {
+        return heapInfo.getTimeStamp();
+    }
+
+    @Override
+    public String toString() {
+        return "[" + new Date(getTimestamp()) +"] ";
+    }
+
+    public ObjectHistogram getHistogram() throws IOException {
+        return heapDAO.getHistogram(heapInfo);
+    }
+
+    public HeapInfo getInfo() {
+        return heapInfo;
+    }
+
+    private synchronized Directory getLuceneIndex() {
+        if (luceneIndex == null) {
+            try {
+                luceneIndex = createLuceneIndex();
+            } catch (IOException ex) {
+                log.log(Level.SEVERE, "Unexpected IO Exception while creating heap dump index", ex);
+                return null;
+            }
+        }
+        return luceneIndex;
+    }
+
+    private Directory createLuceneIndex() throws IOException,
+            CorruptIndexException, LockObtainFailedException {
+
+        loadHeapDumpIfNecessary();
+
+        Enumeration<JavaHeapObject> thingos = snapshot.getThings();
+        Directory dir = new RAMDirectory();
+        IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_36, new SimpleAnalyzer(Version.LUCENE_36));
+        IndexWriter writer = new IndexWriter(dir, indexWriterConfig);
+        while (thingos.hasMoreElements()) {
+            JavaHeapObject thingo = thingos.nextElement();
+            Document doc = new Document();
+            doc.add(new Field(INDEX_FIELD_CLASSNAME, thingo.getClazz().getName(), Field.Store.YES, Field.Index.NOT_ANALYZED));
+            doc.add(new Field(INDEX_FIELD_OBJECT_ID, thingo.getIdString(), Field.Store.YES, Field.Index.NOT_ANALYZED));
+            writer.addDocument(doc);
+        }
+        writer.close();
+        return dir;
+    }
+
+    public Snapshot getSnapshot() {
+        loadHeapDumpIfNecessary();
+        return snapshot;
+    }
+
+    private synchronized void loadHeapDumpIfNecessary() {
+        if (snapshot == null) {
+            try {
+                loadHeapDump();
+            } catch (IOException e) {
+                log.log(Level.SEVERE, "Unexpected IO Exception while loading heap dump", e);
+            }
+        }
+    }
+
+    private void loadHeapDump() throws IOException {
+        String filename = "heapdump-" + heapInfo.getHeapId();
+        File tmpDir = getOrCreateHeapDumpDir();
+        File tmpFile = new File(tmpDir, filename);
+        if (! tmpFile.exists()) {
+            try (InputStream in = heapDAO.getHeapDumpData(heapInfo);) {
+                Files.copy(in, tmpFile.toPath());
+            }
+            
+        }
+        snapshot = Reader.readFile(tmpFile.getAbsolutePath(), true, 0);
+        snapshot.resolve(true);
+    }
+
+    private File getOrCreateHeapDumpDir() throws IOException {
+        String dirname = "thermostat-" + System.getProperty("user.name");
+        File tmpFile = new File(System.getProperty("java.io.tmpdir"), dirname);
+        if (! tmpFile.exists()) {
+            Files.createDirectory(tmpFile.toPath(), PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rwx------")));
+            return tmpFile;
+        } else {
+            if (tmpFile.isDirectory()) {
+                return tmpFile;
+            } else {
+                throw new FileAlreadyExistsException(tmpFile.getAbsolutePath());
+            }
+        }
+    }
+
+    /**
+     * Find objects with class names matching the given pattern
+     * @param wildCardClassNamePattern a case-sensitive wildcard pattern to match class names against
+     * @param limit the maximum number of results to return
+     * @return a collection of object ids that can be used with {@link #findObject(String)}
+     */
+    public Collection<String> searchObjects(String wildCardClassNamePattern, int limit) {
+        Directory searchIndex = getLuceneIndex();
+
+        WildcardQuery query = new WildcardQuery(new Term(INDEX_FIELD_CLASSNAME, wildCardClassNamePattern));
+        Collection<String> results = new ArrayList<String>();
+        try {
+            IndexReader indexReader = IndexReader.open(searchIndex);
+            IndexSearcher searcher = new IndexSearcher(indexReader);
+            TopDocs found = searcher.search(query, limit);
+            for (ScoreDoc scoreDoc : found.scoreDocs) {
+                Document doc = searcher.doc(scoreDoc.doc);
+                String objectId = doc.get(INDEX_FIELD_OBJECT_ID);
+                results.add(objectId);
+            }
+            searcher.close();
+        } catch (IOException e) {
+            log.log(Level.SEVERE, "Unexpected IO Exception while searching heap dump index", e);
+        }
+        return results;
+    }
+
+    public JavaHeapObject findObject(String id) {
+        loadHeapDumpIfNecessary();
+        return snapshot.findThing(id);
+    }
+
+    public boolean equals(Object o) {
+        return o instanceof HeapDump && ((HeapDump) o).heapInfo.equals(heapInfo);
+    }
+
+    public int hashCode() {
+        return heapInfo.hashCode();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/HistogramLoader.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,71 @@
+/*
+ * 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.vm.heap.analysis.common;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+import com.sun.tools.hat.internal.model.Snapshot;
+import com.sun.tools.hat.internal.parser.Reader;
+
+public class HistogramLoader {
+
+    public ObjectHistogram load(String filename) throws IOException {
+        Snapshot snapshot = loadHeapdump(filename);
+        return computeHistogram(snapshot);
+    }
+
+    private Snapshot loadHeapdump(String filename) throws IOException {
+        File heapdump = new File(filename);
+        Snapshot snapshot = Reader.readFile(heapdump.getAbsolutePath(), true, 0);
+        snapshot.resolve(true);
+        return snapshot;
+    }
+
+    private ObjectHistogram computeHistogram(Snapshot snapshot) {
+        Enumeration<JavaHeapObject> thingos = snapshot.getThings();
+        ObjectHistogram histogram = new ObjectHistogram();
+        while (thingos.hasMoreElements()) {
+            JavaHeapObject thingo = thingos.nextElement();
+            histogram.addThing(thingo);
+        }
+        return histogram;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/HistogramRecord.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,83 @@
+/*
+ * 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.vm.heap.analysis.common;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+public class HistogramRecord implements Serializable {
+
+    String classname;
+    long numberOf;
+    long totalSize;
+
+    HistogramRecord(String classname) {
+        this(classname, 0, 0);
+    }
+
+    public HistogramRecord(String classname, long numberOf, long totalSize) {
+        this.classname = classname;
+        this.numberOf = numberOf;
+        this.totalSize = totalSize;
+    }
+
+    public String getClassname() {
+        return classname;
+    }
+
+    public long getNumberOf() {
+        return numberOf;
+    }
+
+    public long getTotalSize() {
+        return totalSize;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (! (o instanceof HistogramRecord)) {
+            return false;
+        }
+        HistogramRecord other = (HistogramRecord) o;
+        return Objects.equals(classname, other.classname) && numberOf == other.numberOf && totalSize == other.totalSize;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(classname, numberOf, totalSize);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/ObjectHistogram.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,73 @@
+/*
+ * 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.vm.heap.analysis.common;
+
+import java.io.PrintStream;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.sun.tools.hat.internal.model.JavaClass;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+
+public class ObjectHistogram implements Serializable {
+
+    private Map<String, HistogramRecord> histogram = new HashMap<>();
+
+    public void addThing(JavaHeapObject thing) {
+        JavaClass clazz = thing.getClazz();
+        HistogramRecord record = histogram.get(clazz.getName());
+        if (record == null) {
+            record = new HistogramRecord(clazz.getName());
+            histogram.put(clazz.getName(), record);
+        }
+        record.numberOf++;
+        record.totalSize += thing.getSize();
+    }
+
+    public Collection<HistogramRecord> getHistogram() {
+        return histogram.values();
+    }
+
+    public void print(PrintStream out) {
+        for (Map.Entry<String, HistogramRecord> entry : histogram.entrySet()) {
+            HistogramRecord record = entry.getValue();
+            out.println(record.classname + ", " + record.numberOf + ", " + record.totalSize);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/Activator.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,79 @@
+/*
+ * 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.vm.heap.analysis.common.internal;
+
+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.storage.core.Storage;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+
+public class Activator implements BundleActivator {
+
+    private ServiceRegistration reg;
+    private ServiceTracker tracker;
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        tracker = new ServiceTracker(context, Storage.class.getName(), null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                Storage storage = (Storage) context.getService(reference);
+                HeapDAO heapDao = new HeapDAOImpl(storage);
+                reg = context.registerService(HeapDAO.class.getName(), heapDao, null);
+                return super.addingService(reference);
+            }
+            
+            @Override
+            public void removedService(ServiceReference reference,
+                    Object service) {
+                reg.unregister();
+                super.removedService(reference, service);
+            }
+        };
+        tracker.open();
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        tracker.close();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImpl.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,164 @@
+/*
+ * 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.vm.heap.analysis.common.internal;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.Cursor;
+import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.core.Query;
+import com.redhat.thermostat.storage.core.Query.Criteria;
+import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.model.HeapInfo;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
+import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram;
+
+public class HeapDAOImpl implements HeapDAO {
+
+    private static final Logger log = LoggingUtils.getLogger(HeapDAOImpl.class);
+
+    private final Storage storage;
+
+    HeapDAOImpl(Storage storage) {
+        this.storage = storage;
+        storage.registerCategory(heapInfoCategory);
+    }
+
+    @Override
+    public void putHeapInfo(HeapInfo heapInfo, File heapDumpData, ObjectHistogram histogramData) throws IOException {
+        heapInfo.setAgentId(storage.getAgentId());
+        String heapId = heapInfo.getAgentId() + "-" + heapInfo.getVmId() + "-" + heapInfo.getTimeStamp();
+        System.err.println("assigning heapId: " + heapId);
+        heapInfo.setHeapId(heapId);
+        String heapDumpId = "heapdump-" + heapId;
+        String histogramId = "histogram-" + heapId;
+        if (heapDumpData != null) {
+            heapInfo.setHeapDumpId(heapDumpId);
+        }
+        if (histogramData != null) {
+            heapInfo.setHistogramId(histogramId);
+        }
+        storage.putPojo(heapInfoCategory, false, heapInfo);
+        if (heapDumpData != null) {
+            storage.saveFile(heapDumpId, new FileInputStream(heapDumpData));
+        }
+        if (histogramData != null) {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            try {
+                ObjectOutputStream oos = new ObjectOutputStream(baos);
+                oos.writeObject(histogramData);
+                ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+                storage.saveFile(histogramId, bais);
+            } catch (IOException e) {
+                e.printStackTrace();
+                log.log(Level.SEVERE, "Unexpected error while writing histogram", e);
+            }
+        }
+    }
+
+    @Override
+    public Collection<HeapInfo> getAllHeapInfo(VmRef vm) {
+        Query query = storage.createQuery()
+                .from(heapInfoCategory)
+                .where(Key.AGENT_ID, Criteria.EQUALS, vm.getAgent().getAgentId())
+                .where(Key.VM_ID, Criteria.EQUALS, vm.getId());
+        Cursor<HeapInfo> cursor = storage.findAllPojos(query, HeapInfo.class);
+        Collection<HeapInfo> heapInfos = new ArrayList<>();
+        while (cursor.hasNext()) {
+            heapInfos.add(cursor.next());
+        }
+        return heapInfos;
+    }
+
+    @Override
+    public InputStream getHeapDumpData(HeapInfo heapInfo) {
+        return storage.loadFile(heapInfo.getHeapDumpId());
+    }
+
+    @Override
+    public ObjectHistogram getHistogram(HeapInfo heapInfo) {
+        
+        try (InputStream in = storage.loadFile(heapInfo.getHistogramId())) {
+            ObjectInputStream ois = new ObjectInputStream(in);
+            return (ObjectHistogram) ois.readObject();
+        } catch (IOException | ClassNotFoundException e) {
+            log.log(Level.SEVERE, "Unexpected error while reading histogram", e);
+            return null;
+        }
+    }
+
+    @Override
+    public HeapInfo getHeapInfo(String heapId) {
+        Query query = storage.createQuery()
+                .from(heapInfoCategory)
+                .where(heapIdKey, Criteria.EQUALS, heapId);
+        HeapInfo found = null;
+        try {
+            found = storage.findPojo(query, HeapInfo.class);
+        } catch (IllegalArgumentException iae) {
+            /*
+             * if the heap id is not found, we get a nice
+             * IllegalArgumentException but check if the illegal argument
+             * exception is caused by that before propagating it.
+             */
+            if (!iae.getMessage().contains("invalid ObjectId")) {
+                throw iae;
+            }
+        }
+        return found;
+    }
+
+    @Override
+    public HeapDump getHeapDump(HeapInfo heapInfo) {
+        return new HeapDump(heapInfo, this);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/HeapDumpTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,140 @@
+/*
+ * 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.vm.heap.analysis.common;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.zip.GZIPInputStream;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.storage.model.HeapInfo;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+
+/*
+ * This testcase uses a minimalistic heapdump that is stored as binary in
+ * src/test/resources.
+ *
+ * It is generated from a simple Java class:
+ * public class Test {
+ *   public static void main(String[] args) throws Exception {
+ *     Thread.sleep(1000000);
+ *   }
+ * }
+ *
+ * The actual heapdump can be generated like this:
+ *
+ * jmap -dump:format=b,file=heapdump.hprof $PID
+ * 
+ * where $PID is the PID of the Java process running the above simple program.
+ *
+ * Finally, the heapdump is gzipped:
+ *
+ * gzip heapdump.hprof
+ *
+ */
+public class HeapDumpTest {
+
+    private static final String HEAP_ID = "TEST_HEAP_ID";
+
+    private HeapDump heapDump;
+
+    @Before
+    public void setUp() throws IOException {
+        InputStream in = getClass().getResourceAsStream("/heapdump.hprof.gz");
+        GZIPInputStream gzipIn = new GZIPInputStream(in);
+
+        HeapInfo heapInfo = mock(HeapInfo.class);
+        when(heapInfo.getHeapId()).thenReturn(HEAP_ID);
+        HeapDAO heapDAO = mock(HeapDAO.class);
+        when(heapDAO.getHeapDumpData(heapInfo)).thenReturn(gzipIn);
+        heapDump = new HeapDump(heapInfo, heapDAO);
+    }
+
+    @Test
+    public void testSearchObjects() {
+        Collection<String> foundObjectIds = heapDump.searchObjects("java.util.ArrayDeque", 10);
+        assertEquals(8, foundObjectIds.size());
+        assertTrue(foundObjectIds.contains("0x7d704eb20"));
+        assertTrue(foundObjectIds.contains("0x7d70485e8"));
+        assertTrue(foundObjectIds.contains("0x7d704aed8"));
+        assertTrue(foundObjectIds.contains("0x7d70447a0"));
+        assertTrue(foundObjectIds.contains("0x7d704d438"));
+        assertTrue(foundObjectIds.contains("0x7d70471e8"));
+        assertTrue(foundObjectIds.contains("0x7d7049aa0"));
+        assertTrue(foundObjectIds.contains("0x7d704bfe0"));
+    }
+
+    @Test
+    public void testSearchObjectsWithLimit() {
+        Collection<String> foundObjectIds = heapDump.searchObjects("java.util.ArrayDeque", 2);
+        assertEquals(2, foundObjectIds.size());
+        // we know 2 things matched. Don't know which ones (there is no guarentee on order).
+        String[] possibleMatches = new String[] {
+            "0x7d704eb20",
+            "0x7d70485e8",
+            "0x7d704aed8",
+            "0x7d70447a0",
+            "0x7d704d438",
+            "0x7d70471e8",
+            "0x7d7049aa0",
+            "0x7d704bfe0",
+        };
+        int totalMatches = 0;
+        for (String possible : possibleMatches) {
+            if (foundObjectIds.contains(possible)) {
+                totalMatches++;
+            }
+        }
+        assertEquals(2, totalMatches);
+    }
+
+    @Test
+    public void testFindObject() {
+        JavaHeapObject obj = heapDump.findObject("0x7d704eb20");
+        assertEquals("0x7d704eb20", obj.getIdString());
+        assertEquals("java.util.ArrayDeque", obj.getClazz().getName());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOTest.java	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,286 @@
+/*
+ * 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.vm.heap.analysis.common.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectOutputStream;
+import java.util.Collection;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.storage.core.Category;
+import com.redhat.thermostat.storage.core.Cursor;
+import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.core.Query;
+import com.redhat.thermostat.storage.core.Query.Criteria;
+import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.model.HeapInfo;
+import com.redhat.thermostat.test.MockQuery;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import com.redhat.thermostat.vm.heap.analysis.common.HistogramRecord;
+import com.redhat.thermostat.vm.heap.analysis.common.ObjectHistogram;
+import com.sun.tools.hat.internal.model.JavaClass;
+import com.sun.tools.hat.internal.model.JavaHeapObject;
+
+
+public class HeapDAOTest {
+
+    private HeapDAO dao;
+    private Storage storage;
+    private HeapInfo heapInfo;
+    private File heapDumpData;
+    private ObjectHistogram histogram;
+    private InputStream histogramData;
+
+    @Before
+    public void setUp() throws IOException {
+        storage = mock(Storage.class);
+        when(storage.getAgentId()).thenReturn("test");
+        when(storage.createQuery()).then(new Answer<Query>() {
+            @Override
+            public Query answer(InvocationOnMock invocation) throws Throwable {
+                return new MockQuery();
+            }
+        });
+
+        dao = new HeapDAOImpl(storage);
+        
+        heapInfo = new HeapInfo(123, 12345);
+        byte[] data = new byte[] { 1, 2, 3 };
+        heapDumpData = File.createTempFile("test", "test");
+        FileOutputStream out = new FileOutputStream(heapDumpData);
+        out.write(data);
+        out.close();
+        histogramData = createHistogramData();
+
+        // Setup for reading data from DB.
+        MockQuery findAllQuery = new MockQuery()
+            .from(HeapDAO.heapInfoCategory)
+            .where(Key.AGENT_ID, Criteria.EQUALS, "123")
+            .where(Key.VM_ID, Criteria.EQUALS, 234);
+
+        @SuppressWarnings("unchecked")
+        Cursor<HeapInfo> cursor = mock(Cursor.class);
+        HeapInfo info1 = new HeapInfo(234, 12345L);
+        info1.setAgentId("123");
+        info1.setHeapDumpId("test1");
+        info1.setHistogramId("histotest1");
+
+        HeapInfo info2 = new HeapInfo(234, 23456L);
+        info2.setAgentId("123");
+        info2.setHeapDumpId("test2");
+        info2.setHistogramId("histotest2");
+
+        when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
+        when(cursor.next()).thenReturn(info1).thenReturn(info2).thenReturn(null);
+        when(storage.findAllPojos(findAllQuery, HeapInfo.class)).thenReturn(cursor);
+
+        // Setup for reading heapdump data.
+        when(storage.loadFile("test-heap")).thenReturn(new ByteArrayInputStream(data));
+        when(storage.loadFile("test-histo")).thenReturn(histogramData);
+
+        // We dont check for AGENT_ID. That's enforced/added/checked by Storage
+
+    }
+
+    private InputStream createHistogramData() throws IOException {
+        histogram = new ObjectHistogram();
+
+        JavaClass cls1 = mock(JavaClass.class);
+        JavaHeapObject obj1 = mock(JavaHeapObject.class);
+        when(cls1.getName()).thenReturn("class1");
+        when(obj1.getClazz()).thenReturn(cls1);
+        when(obj1.getSize()).thenReturn(5);
+        JavaHeapObject obj2 = mock(JavaHeapObject.class);
+        when(obj2.getClazz()).thenReturn(cls1);
+        when(obj2.getSize()).thenReturn(3);
+        JavaClass cls2 = mock(JavaClass.class);
+        JavaHeapObject obj3 = mock(JavaHeapObject.class);
+        when(cls2.getName()).thenReturn("class2");
+        when(obj3.getClazz()).thenReturn(cls2);
+        when(obj3.getSize()).thenReturn(10);
+
+        histogram.addThing(obj1);
+        histogram.addThing(obj2);
+        histogram.addThing(obj3);
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(baos);
+        oos.writeObject(histogram);
+        return new ByteArrayInputStream(baos.toByteArray());
+    }
+
+    @After
+    public void tearDown() {
+        histogramData = null;
+        histogram = null;
+        heapDumpData.delete();
+        heapDumpData = null;
+        heapInfo = null;
+        dao = null;
+        storage = null;
+    }
+
+    @Test
+    public void testCategory() {
+        Category category = HeapDAO.heapInfoCategory;
+        assertNotNull(category);
+        assertEquals("vm-heap-info", category.getName());
+        Collection<Key<?>> keys = category.getKeys();
+        assertEquals(6, keys.size());
+        assertTrue(keys.contains(new Key<>("agentId", true)));
+        assertTrue(keys.contains(new Key<>("vmId", true)));
+        assertTrue(keys.contains(new Key<>("timeStamp", false)));
+        assertTrue(keys.contains(new Key<>("heapId", false)));
+        assertTrue(keys.contains(new Key<>("heapDumpId", false)));
+        assertTrue(keys.contains(new Key<>("histogramId", false)));
+    }
+
+    @Test
+    public void testPutHeapInfo() throws IOException {
+        dao.putHeapInfo(heapInfo, heapDumpData, histogram);
+
+        verify(storage).putPojo(HeapDAO.heapInfoCategory, false, heapInfo);
+
+        ArgumentCaptor<InputStream> data = ArgumentCaptor.forClass(InputStream.class);
+        verify(storage).saveFile(eq("heapdump-test-123-12345"), data.capture());
+        InputStream in = data.getValue();
+        assertEquals(1, in.read());
+        assertEquals(2, in.read());
+        assertEquals(3, in.read());
+        assertEquals(-1, in.read());
+        assertEquals("test-123-12345", heapInfo.getHeapId());
+        ArgumentCaptor<InputStream> histoStream = ArgumentCaptor.forClass(InputStream.class);
+        verify(storage).saveFile(eq("histogram-test-123-12345"), histoStream.capture());
+        InputStream histoActual = histoStream.getValue();
+        int expected;
+        int actual;
+        do {
+            expected = histogramData.read();
+            actual = histoActual.read();
+            assertEquals(expected, actual);
+        } while (expected != -1 && actual != -1);
+    }
+
+    @Test
+    public void testPutHeapInfoWithoutDump() throws IOException {
+        dao.putHeapInfo(heapInfo, null, null);
+
+        verify(storage).putPojo(HeapDAO.heapInfoCategory, false, heapInfo);
+
+        verify(storage, never()).saveFile(anyString(), any(InputStream.class));
+        assertEquals("test-123-12345", heapInfo.getHeapId());
+    }
+
+    @Test
+    public void testGetAllHeapInfo() {
+        
+        // verify a connection key has been created before requesting the
+        // heap dumps
+        verify(storage).registerCategory(HeapDAO.heapInfoCategory);
+        
+        HostRef host = new HostRef("123", "test-host");
+        VmRef vm = new VmRef(host, 234, "test-vm");
+        Collection<HeapInfo> heapInfos = dao.getAllHeapInfo(vm);
+        
+        HeapInfo info1 = new HeapInfo(234, 12345);
+        info1.setHeapDumpId("test1");
+        info1.setHistogramId("histotest1");
+        
+        HeapInfo info2 = new HeapInfo(234, 23456);
+        info2.setHeapDumpId("test2");
+        info2.setHistogramId("histotest2");
+        
+        assertEquals(2, heapInfos.size());
+        assertTrue(heapInfos.contains(info1));
+        assertTrue(heapInfos.contains(info2));
+    }
+
+    @Test
+    public void testGetHeapDump() throws IOException {
+        heapInfo.setHeapDumpId("test-heap");
+        InputStream in = dao.getHeapDumpData(heapInfo);
+        assertEquals(1, in.read());
+        assertEquals(2, in.read());
+        assertEquals(3, in.read());
+        assertEquals(-1, in.read());
+    }
+
+    @Test
+    public void testGetHistogram() throws IOException {
+        heapInfo.setHistogramId("test-histo");
+        ObjectHistogram histo = dao.getHistogram(heapInfo);
+        Collection<HistogramRecord> histoRecs = histo.getHistogram();
+        assertEquals(2, histoRecs.size());
+        assertTrue(histoRecs.contains(new HistogramRecord("class1", 2, 8)));
+        assertTrue(histoRecs.contains(new HistogramRecord("class2", 1, 10)));
+    }
+
+    @Test
+    public void testInvalidHeapId() throws IOException {
+        storage = mock(Storage.class);
+        when(storage.createQuery()).thenReturn(new MockQuery());
+        when(storage.findPojo(any(Query.class), same(HeapInfo.class))).thenThrow(new IllegalArgumentException("invalid ObjectId"));
+        dao = new HeapDAOImpl(storage);
+        heapInfo = dao.getHeapInfo("some-random-heap-id");
+        assertTrue(heapInfo == null);
+    }
+}
Binary file vm-heap-analysis/common/src/test/resources/heapdump.hprof.gz has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/pom.xml	Wed Dec 12 15:52:00 2012 -0500
@@ -0,0 +1,61 @@
+<?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</artifactId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>thermostat-vm-heap-analysis</artifactId>
+  <packaging>pom</packaging>
+
+  <name>Thermostat VM Heap Analysis plugin</name>
+
+  <modules>
+    <module>agent</module>
+    <module>client-core</module>
+    <module>client-swing</module>
+    <module>command</module>
+    <module>common</module>
+  </modules>
+
+</project>