changeset 750:bc6fadf5ceaa

Merge
author Roman Kennke <rkennke@redhat.com>
date Fri, 26 Oct 2012 15:32:56 +0200
parents 769d409c83b6 (current diff) c8985141906e (diff)
children 6c7b3cdb01c6
files client/core/src/main/java/com/redhat/thermostat/client/internal/ChangeableText.java client/core/src/main/java/com/redhat/thermostat/client/internal/GUIClientCommand.java client/core/src/main/java/com/redhat/thermostat/client/internal/HostFilterRegistry.java client/core/src/main/java/com/redhat/thermostat/client/internal/HostIconDecorator.java client/core/src/main/java/com/redhat/thermostat/client/internal/HostTreeDecoratorRegistry.java client/core/src/main/java/com/redhat/thermostat/client/internal/Main.java client/core/src/main/java/com/redhat/thermostat/client/internal/MainView.java client/core/src/main/java/com/redhat/thermostat/client/internal/MainWindowControllerImpl.java client/core/src/main/java/com/redhat/thermostat/client/internal/MenuRegistry.java client/core/src/main/java/com/redhat/thermostat/client/internal/RegistryFactory.java client/core/src/main/java/com/redhat/thermostat/client/internal/UiFacadeFactoryImpl.java client/core/src/main/java/com/redhat/thermostat/client/internal/VMInformationRegistry.java client/core/src/main/java/com/redhat/thermostat/client/internal/VMTreeDecoratorRegistry.java client/core/src/main/java/com/redhat/thermostat/client/internal/VmFilterRegistry.java client/core/src/main/java/com/redhat/thermostat/client/internal/config/ConnectionConfiguration.java client/core/src/main/java/com/redhat/thermostat/client/internal/osgi/ApplicationServiceProvider.java client/core/src/main/java/com/redhat/thermostat/client/internal/osgi/ContextActionServiceProvider.java client/core/src/main/java/com/redhat/thermostat/client/internal/osgi/ThermostatActivator.java client/core/src/main/java/com/redhat/thermostat/client/internal/osgi/VMContextActionServiceTracker.java client/core/src/main/java/com/redhat/thermostat/client/internal/osgi/VmInformationServiceTracker.java client/core/src/main/java/com/redhat/thermostat/client/internal/ui/swing/AboutDialog.java client/core/src/main/java/com/redhat/thermostat/client/internal/ui/swing/WrapLayout.java client/core/src/main/java/com/redhat/thermostat/client/swing/SwingAgentInformationViewProvider.java client/core/src/main/java/com/redhat/thermostat/client/swing/SwingClientConfigurationViewProvider.java client/core/src/main/java/com/redhat/thermostat/client/swing/SwingHostCpuViewProvider.java client/core/src/main/java/com/redhat/thermostat/client/swing/SwingHostInformationViewProvider.java client/core/src/main/java/com/redhat/thermostat/client/swing/SwingHostMemoryViewProvider.java client/core/src/main/java/com/redhat/thermostat/client/swing/SwingHostOverviewViewProvider.java client/core/src/main/java/com/redhat/thermostat/client/swing/SwingSummaryViewProvider.java client/core/src/main/java/com/redhat/thermostat/client/swing/SwingVmCpuViewProvider.java client/core/src/main/java/com/redhat/thermostat/client/swing/SwingVmGcViewProvider.java client/core/src/main/java/com/redhat/thermostat/client/swing/SwingVmInformationViewProvider.java client/core/src/main/java/com/redhat/thermostat/client/swing/SwingVmOverviewViewProvider.java client/core/src/main/java/com/redhat/thermostat/client/ui/AgentInformationDisplayFrame.java client/core/src/main/java/com/redhat/thermostat/client/ui/ClientConfigurationPanel.java client/core/src/main/java/com/redhat/thermostat/client/ui/ClientConfigurationSwing.java client/core/src/main/java/com/redhat/thermostat/client/ui/Components.java client/core/src/main/java/com/redhat/thermostat/client/ui/DecoratedDefaultMutableTreeNode.java client/core/src/main/java/com/redhat/thermostat/client/ui/HostCpuPanel.java client/core/src/main/java/com/redhat/thermostat/client/ui/HostInformationPanel.java client/core/src/main/java/com/redhat/thermostat/client/ui/HostMemoryPanel.java client/core/src/main/java/com/redhat/thermostat/client/ui/HostOverviewPanel.java client/core/src/main/java/com/redhat/thermostat/client/ui/HtmlTextBuilder.java client/core/src/main/java/com/redhat/thermostat/client/ui/IconResource.java client/core/src/main/java/com/redhat/thermostat/client/ui/LabelField.java client/core/src/main/java/com/redhat/thermostat/client/ui/LayoutDebugHelper.java client/core/src/main/java/com/redhat/thermostat/client/ui/MainWindow.java client/core/src/main/java/com/redhat/thermostat/client/ui/MemorySpacePanel.java client/core/src/main/java/com/redhat/thermostat/client/ui/MenuHelper.java client/core/src/main/java/com/redhat/thermostat/client/ui/RecentTimeSeriesChartPanel.java client/core/src/main/java/com/redhat/thermostat/client/ui/SearchFieldSwingView.java client/core/src/main/java/com/redhat/thermostat/client/ui/SearchFieldView.java client/core/src/main/java/com/redhat/thermostat/client/ui/SectionHeader.java client/core/src/main/java/com/redhat/thermostat/client/ui/SimpleTable.java client/core/src/main/java/com/redhat/thermostat/client/ui/SummaryPanel.java client/core/src/main/java/com/redhat/thermostat/client/ui/SwingComponent.java client/core/src/main/java/com/redhat/thermostat/client/ui/UIResources.java client/core/src/main/java/com/redhat/thermostat/client/ui/ValueField.java client/core/src/main/java/com/redhat/thermostat/client/ui/VmCpuPanel.java client/core/src/main/java/com/redhat/thermostat/client/ui/VmGcController.java client/core/src/main/java/com/redhat/thermostat/client/ui/VmGcPanel.java client/core/src/main/java/com/redhat/thermostat/client/ui/VmInformationPanel.java client/core/src/main/java/com/redhat/thermostat/client/ui/VmOverviewPanel.java client/core/src/main/resources/duke.png client/core/src/test/java/com/redhat/thermostat/client/internal/GUIClientCommandTest.java client/core/src/test/java/com/redhat/thermostat/client/internal/HostIconDecoratorTest.java client/core/src/test/java/com/redhat/thermostat/client/internal/MainTest.java client/core/src/test/java/com/redhat/thermostat/client/internal/MainWindowControllerImplTest.java client/core/src/test/java/com/redhat/thermostat/client/internal/MenuRegistryTest.java client/core/src/test/java/com/redhat/thermostat/client/internal/SearchFieldSwingViewTest.java client/core/src/test/java/com/redhat/thermostat/client/internal/osgi/ApplicationServiceProviderTest.java client/core/src/test/java/com/redhat/thermostat/client/internal/osgi/ThermostatActivatorTest.java client/core/src/test/java/com/redhat/thermostat/client/ui/AgentInformationDisplayFrameTest.java client/core/src/test/java/com/redhat/thermostat/client/ui/ClientConfigurationSwingTest.java client/core/src/test/java/com/redhat/thermostat/client/ui/HostInformationPanelTest.java client/core/src/test/java/com/redhat/thermostat/client/ui/IconDescriptorTest.java client/core/src/test/java/com/redhat/thermostat/client/ui/MainWindowTest.java client/core/src/test/java/com/redhat/thermostat/client/ui/MenuHelperTest.java client/core/src/test/java/com/redhat/thermostat/client/ui/TabbedPaneMatcher.java client/core/src/test/java/com/redhat/thermostat/client/ui/UIResourcesTest.java client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapDumpController.java client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/HeapDumpControllerTest.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/Activator.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumpController.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumpDetailsController.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumpDetailsView.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumpDetailsViewProvider.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumperService.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapHistogramView.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapHistogramViewProvider.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapObjectUI.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapView.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapViewProvider.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/Histogram.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/LocaleResources.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/ObjectDetailsController.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/ObjectDetailsView.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/ObjectDetailsViewProvider.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/ObjectRootsController.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/ObjectRootsView.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/ObjectRootsViewProvider.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/PrintObjectUtils.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/chart/OverviewChart.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/cli/DumpHeapCommand.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/cli/FindObjectsCommand.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/cli/FindRoot.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/cli/FindRootCommand.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommand.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/cli/HeapNotFoundException.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/cli/HeapPath.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/cli/ListHeapDumpsCommand.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/cli/ObjectCommandHelper.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/cli/ObjectInfoCommand.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/cli/ObjectNotFoundException.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/cli/SaveHeapDumpToFileCommand.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/cli/ShowHeapHistogramCommand.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/HeapDetailsSwing.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/HeapPanel.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/HeapSwingView.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/HistogramPanel.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/LazyMutableTreeNode.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/ObjectDetailsPanel.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/ObjectRootsFrame.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/StatsPanel.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/SwingHeapDumpDetailsViewProvider.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/SwingHeapHistogramViewProvider.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/SwingHeapViewProvider.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/SwingObjectDetailsViewProvider.java client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/SwingObjectRootsViewProvider.java client/heapdumper/src/main/resources/META-INF/services/com.redhat.thermostat.common.cli.Command client/heapdumper/src/main/resources/com/redhat/thermostat/client/heap/strings.properties client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/HeapDumpControllerTest.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/HeapDumpDetailsControllerTest.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/LocaleResourcesTest.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/ObjectDetailsControllerTest.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/ObjectRootsControllerTest.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/ServicesAvailableActionTest.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/cli/DumpHeapCommandTest.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/cli/FindObjectsCommandTest.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/cli/FindRootCommandTest.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommandTest.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/cli/ListHeapDumpsCommandTest.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/cli/ObjectInfoCommandTest.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/cli/SaveHeapDumpToFileCommandTest.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/cli/ShowHeapHistogramCommandTest.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/swing/HeapDetailsSwingTest.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/swing/HeapSwingViewTest.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/swing/ObjectDetailsPanelTest.java client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/swing/ObjectRootsFrameTest.java client/living-vm-filter/src/main/java/com/redhat/thermostat/client/filter/vm/DeadVMDecorator.java client/living-vm-filter/src/main/java/com/redhat/thermostat/client/filter/vm/LivingVMFilter.java client/living-vm-filter/src/main/java/com/redhat/thermostat/client/filter/vm/LivingVMFilterMenuAction.java client/living-vm-filter/src/main/java/com/redhat/thermostat/client/filter/vm/VMDecorator.java client/living-vm-filter/src/main/java/com/redhat/thermostat/client/filter/vm/VMFilterActivator.java client/living-vm-filter/src/main/resources/deadvm.png client/living-vm-filter/src/test/java/com/redhat/thermostat/client/filter/vm/LivingVMFilterTest.java client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/MemoryStatsController.java client/memory-stats-panel/core/src/test/java/com/redhat/thermostat/client/stats/memory/core/MemoryStatsControllerTest.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryGraphPanel.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryMeter.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsController.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsPanelActivator.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsService.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsView.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsViewImpl.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsViewProvider.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/Payload.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/RangeModel.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/StatsModel.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/SwingMemoryStatsViewProvider.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/locale/LocaleResources.java client/memory-stats-panel/src/main/resources/com/redhat/thermostat/client/stats/memory/locale/strings.properties client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/MemoryStatsControllerTest.java client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/MemoryStatsPanelActivatorTest.java client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/PayloadTest.java client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/RangeModelTest.java client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/StatsModelTest.java client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/locale/TranslateTest.java client/swing-components/pom.xml client/swing-components/src/main/java/com/redhat/thermostat/charts/BytesTickUnit.java client/swing-components/src/main/java/com/redhat/thermostat/swing/ActionButton.java client/swing-components/src/main/java/com/redhat/thermostat/swing/ActionButtonUI.java client/swing-components/src/main/java/com/redhat/thermostat/swing/ActionToggleButton.java client/swing-components/src/main/java/com/redhat/thermostat/swing/ChartPanel.java client/swing-components/src/main/java/com/redhat/thermostat/swing/DebugBorder.java client/swing-components/src/main/java/com/redhat/thermostat/swing/EdtHelper.java client/swing-components/src/main/java/com/redhat/thermostat/swing/EmptyIcon.java client/swing-components/src/main/java/com/redhat/thermostat/swing/GradientPanel.java client/swing-components/src/main/java/com/redhat/thermostat/swing/GradientRoundBorder.java client/swing-components/src/main/java/com/redhat/thermostat/swing/GraphicsUtils.java client/swing-components/src/main/java/com/redhat/thermostat/swing/HeaderPanel.java client/swing-components/src/main/java/com/redhat/thermostat/swing/Palette.java client/swing-components/src/main/java/com/redhat/thermostat/swing/ShadowLabel.java client/swing-components/src/main/java/com/redhat/thermostat/swing/StatusBar.java client/swing-components/src/main/java/com/redhat/thermostat/swing/ThermostatTable.java client/swing-components/src/main/java/com/redhat/thermostat/swing/ThermostatTableColumnResizer.java client/swing-components/src/main/java/com/redhat/thermostat/swing/ThermostatTableRenderer.java client/swing-components/src/main/java/com/redhat/thermostat/swing/ToolbarButton.java client/swing-components/src/main/java/com/redhat/thermostat/swing/models/LongRange.java client/swing-components/src/main/java/com/redhat/thermostat/swing/models/LongRangeNormalizer.java client/swing-components/src/main/java/com/redhat/thermostat/swing/models/NullSelectionModel.java client/swing-components/src/main/resources/icons/resize-grip.png client/swing-components/src/main/resources/icons/resize-grip.svg client/swing-components/src/main/resources/icons/scale-slider-vert-backdrop.png client/swing-components/src/main/resources/icons/scale-slider-vert.png client/swing-components/src/test/java/com/redhat/thermostat/swing/EdtHelperTest.java client/swing-components/src/test/java/com/redhat/thermostat/swing/StatusBarTest.java client/swing-components/src/test/java/com/redhat/thermostat/swing/models/LongRangeNormalizerTest.java client/swing-components/src/test/java/com/redhat/thermostat/swing/models/NullSelectionModelTest.java client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/Activator.java client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/LocaleResources.java client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/SwingVmClassStatViewProvider.java client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/VmClassStatController.java client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/VmClassStatPanel.java client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/VmClassStatService.java client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/VmClassStatView.java client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/VmClassStatViewProvider.java client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/locale/LocaleResources.java client/vmclassstat/src/main/resources/com/redhat/thermostat/client/vmclassstat/locale/strings.properties client/vmclassstat/src/main/resources/com/redhat/thermostat/client/vmclassstat/strings.properties client/vmclassstat/src/test/java/com/redhat/thermostat/client/vmclassstat/ActivatorTest.java client/vmclassstat/src/test/java/com/redhat/thermostat/client/vmclassstat/LocaleResourcesTest.java client/vmclassstat/src/test/java/com/redhat/thermostat/client/vmclassstat/VmClassStatControllerTest.java client/vmclassstat/src/test/java/com/redhat/thermostat/client/vmclassstat/VmClassStatPanelTest.java client/vmclassstat/src/test/java/com/redhat/thermostat/client/vmclassstat/locale/TranslateTest.java common/core/p2.inf common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java common/core/src/test/java/com/redhat/thermostat/common/storage/MongoStorageTest.java distribution/config/commands/gui.properties distribution/config/commands/service.properties distribution/config/osgi-export.properties launcher/src/test/java/com/redhat/thermostat/launcher/LauncherTest.java pom.xml thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/VMCapsSummaryPanel.java web/client/pom.xml~ web/common/pom.xml~ web/server/pom.xml~
diffstat 607 files changed, 36423 insertions(+), 28658 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Fri Oct 26 13:13:42 2012 +0200
+++ b/.hgignore	Fri Oct 26 15:32:56 2012 +0200
@@ -10,3 +10,4 @@
 syntax: glob
 target/*
 bin/*
+*~
--- a/Makefile	Fri Oct 26 13:13:42 2012 +0200
+++ b/Makefile	Fri Oct 26 15:32:56 2012 +0200
@@ -1,7 +1,7 @@
-MAVEN           = mvn
-SKIP_TESTS      = false
-REPO_LOC        = $(HOME)/.thermostat/.build/mvn_repository
-MAVEN_FLAGS     = 
+MAVEN           ?= mvn
+SKIP_TESTS      ?= false
+REPO_LOC        ?= $(HOME)/.thermostat/.build/mvn_repository
+MAVEN_FLAGS     ?= 
 
 #
 # Do not change anything below
@@ -14,7 +14,10 @@
 	MAVEN_SKIP_TEST = -Dmaven.test.skip=true
 endif
 
-all: eclipse
+# Default to cleaning the local repo and building core + eclipse
+# Cleaning the repo prevents things like not seeing build failures
+# after bundles have been renamed.
+all: clean-repo eclipse
 
 core:
 	$(MAVEN) -f $(POM) $(MAVEN_FLAGS) $(MAVEN_SKIP_TEST) clean $(GOAL)
@@ -28,7 +31,13 @@
 eclipse-test-p2: eclipse-test-deps
 	$(MAVEN) -f eclipse/test-deps-p2-repository/pom.xml $(MAVEN_FLAGS) $(REPO_FLAG) $(MAVEN_SKIP_TEST) clean $(GOAL)
 
-eclipse: eclipse-test-p2
+jfreechart-deps: core-install
+	$(MAVEN) -f eclipse/jfreechart-bundle-wrapping/pom.xml $(MAVEN_FLAGS) $(REPO_FLAG) $(MAVEN_SKIP_TEST) clean install
+
+jfreechart-p2: jfreechart-deps
+	$(MAVEN) -f eclipse/jfreechart-p2-repository/pom.xml $(MAVEN_FLAGS) $(REPO_FLAG) $(MAVEN_SKIP_TEST) clean $(GOAL)
+
+eclipse: eclipse-test-p2 jfreechart-p2
 	$(MAVEN) -f eclipse/pom.xml $(MAVEN_FLAGS) $(REPO_FLAG) $(MAVEN_SKIP_TEST) clean $(GOAL)
 
 create-repo-dir:
--- a/bundles/src/main/java/com/redhat/thermostat/bundles/OSGiRegistry.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/bundles/src/main/java/com/redhat/thermostat/bundles/OSGiRegistry.java	Fri Oct 26 15:32:56 2012 +0200
@@ -44,6 +44,7 @@
 
 import com.redhat.thermostat.bundles.impl.BundleLoader;
 import com.redhat.thermostat.common.Configuration;
+import com.redhat.thermostat.common.cli.CommandInfoNotFoundException;
 import com.redhat.thermostat.common.cli.CommandInfoSource;
 
 
@@ -53,7 +54,7 @@
 
     public abstract void setCommandInfoSource(CommandInfoSource source);
 
-    public abstract void addBundlesFor(String commandName) throws BundleException, IOException;
+    public abstract void addBundlesFor(String commandName) throws BundleException, CommandInfoNotFoundException, IOException;
 
     public static void preLoadBundles(Framework framework, List<String> bundleLocations,
             boolean printOSGiInfo) throws BundleException {
--- a/bundles/src/main/java/com/redhat/thermostat/bundles/impl/OSGiRegistryImpl.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/bundles/src/main/java/com/redhat/thermostat/bundles/impl/OSGiRegistryImpl.java	Fri Oct 26 15:32:56 2012 +0200
@@ -39,6 +39,7 @@
 import com.redhat.thermostat.bundles.OSGiRegistry;
 import com.redhat.thermostat.common.Configuration;
 import com.redhat.thermostat.common.ConfigurationException;
+import com.redhat.thermostat.common.cli.CommandInfoNotFoundException;
 import com.redhat.thermostat.common.cli.CommandInfoSource;
 
 import java.io.FileNotFoundException;
@@ -86,7 +87,7 @@
     }
 
     @Override
-    public void addBundlesFor(String commandName) throws BundleException, IOException {
+    public void addBundlesFor(String commandName) throws BundleException, IOException, CommandInfoNotFoundException {
         if (configuration.getPrintOSGiInfo()) {
             System.out.println("Loading additional bundles for: " + commandName);
         }
--- a/client/core/pom.xml	Fri Oct 26 13:13:42 2012 +0200
+++ b/client/core/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -51,13 +51,6 @@
   <name>Thermostat Client Core</name>
 
   <dependencies>
-  
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-laf</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    
     <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
@@ -69,16 +62,6 @@
       <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.powermock</groupId>
       <artifactId>powermock-api-mockito</artifactId>
       <scope>test</scope>
@@ -110,33 +93,10 @@
       <artifactId>org.osgi.compendium</artifactId>
       <scope>provided</scope>
     </dependency>
-
-    <dependency>
-    	<groupId>com.redhat.thermostat</groupId>
-    	<artifactId>thermostat-swing-components</artifactId>
-    	<version>${project.version}</version>
-    </dependency>
   </dependencies>
 
   <build>
 
-    <resources>
-      <resource>
-        <directory>src/main/resources</directory>
-        <filtering>true</filtering>
-        <excludes>
-          <exclude>**/*.png</exclude>
-        </excludes>
-      </resource>
-      <resource>
-        <directory>src/main/resources</directory>
-        <filtering>false</filtering>
-        <includes>
-          <include>**/*.png</include>
-        </includes>
-      </resource>
-    </resources>
-
     <plugins>
       <plugin>
         <groupId>org.apache.felix</groupId>
@@ -145,26 +105,16 @@
         <configuration>
           <instructions>
             <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
-            <Bundle-Activator>com.redhat.thermostat.client.internal.osgi.ThermostatActivator</Bundle-Activator>
             <Bundle-SymbolicName>com.redhat.thermostat.client.core</Bundle-SymbolicName>
             <Export-Package>
               com.redhat.thermostat.client.osgi.service,
               com.redhat.thermostat.client.ui,
               com.redhat.thermostat.client.locale,
-              <!-- Contains Swing view providers -->
-              com.redhat.thermostat.client.swing,
               <!-- Interfaces for views, controllers, etc. -->
               com.redhat.thermostat.client.core,
               com.redhat.thermostat.client.core.controllers,
-              com.redhat.thermostat.client.core.views,
+              com.redhat.thermostat.client.core.views
             </Export-Package>
-            <Private-Package>
-              com.redhat.thermostat.client.internal,
-              com.redhat.thermostat.client.internal.config,
-              com.redhat.thermostat.client.internal.osgi,
-              com.redhat.thermostat.client.internal.ui,
-              com.redhat.thermostat.client.internal.ui.swing
-            </Private-Package>
             <!-- Do not autogenerate uses clauses in Manifests -->
             <_nouses>true</_nouses>
           </instructions>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/core/src/main/java/com/redhat/thermostat/client/core/views/SearchFieldView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.core.views;
+
+import com.redhat.thermostat.client.core.views.View;
+import com.redhat.thermostat.common.ActionListener;
+
+public interface SearchFieldView extends View {
+
+    /** For use by tests only */
+    public static final String VIEW_NAME = "searchField";
+
+    public enum SearchAction {
+        TEXT_CHANGED,
+        PERFORM_SEARCH,
+    }
+
+    public String getSearchText();
+
+    public void setSearchText(String text);
+
+    void setLabel(String label);
+
+    void setTooltip(String tooltip);
+
+    public void addActionListener(ActionListener<SearchAction> listener);
+    public void removeActionListener(ActionListener<SearchAction> listener);
+
+}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/ChangeableText.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.internal;
-
-import java.util.HashSet;
-import java.util.Set;
-
-public class ChangeableText {
-
-    private final Set<TextListener> listeners = new HashSet<TextListener>();
-    private String text;
-
-    public static interface TextListener {
-        public void textChanged(ChangeableText text);
-    }
-
-    public ChangeableText(String text) {
-        this.text = text;
-    }
-
-    public synchronized void setText(String text) {
-        if (this.text.equals(text)) {
-            return;
-        }
-        this.text = text;
-        fireChanged();
-    }
-
-    public synchronized String getText() {
-        return text;
-    }
-
-    public synchronized void addListener(TextListener listener) {
-        this.listeners.add(listener);
-    }
-
-    public synchronized void removeListener(TextListener listener) {
-        this.listeners.remove(listener);
-    }
-
-    private void fireChanged() {
-        for (TextListener listener: listeners) {
-            listener.textChanged(this);
-        }
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/GUIClientCommand.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.internal;
-
-import org.osgi.framework.BundleContext;
-
-import com.redhat.thermostat.client.internal.osgi.ApplicationServiceProvider;
-import com.redhat.thermostat.client.internal.osgi.ContextActionServiceProvider;
-import com.redhat.thermostat.client.osgi.service.ApplicationService;
-import com.redhat.thermostat.client.osgi.service.ContextAction;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.cli.OSGiContext;
-import com.redhat.thermostat.common.cli.SimpleCommand;
-
-public class GUIClientCommand extends SimpleCommand implements OSGiContext {
-
-    private BundleContext context;
-    private Main clientMain;
-
-    public GUIClientCommand(Main clientMain) {
-        this.clientMain = clientMain;
-    }
-
-    @Override
-    public void setBundleContext(BundleContext context) {
-        this.context = context;
-    }
-    
-    @Override
-    public void run(CommandContext ctx) throws CommandException {
-        ApplicationService service = new ApplicationServiceProvider();
-        
-        context.registerService(ApplicationService.class.getName(), service, null);
-        context.registerService(ContextAction.class.getName(), new ContextActionServiceProvider(), null);
-        
-        // this blocks, everything else needs to be done before
-        clientMain.run();
-
-        service.getApplicationExecutor().shutdown();
-    }
-
-    @Override
-    public String getName() {
-        return "gui";
-    }
-
-    @Override
-    public boolean isStorageRequired() {
-        return false;
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/HostFilterRegistry.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.internal;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.InvalidSyntaxException;
-
-import com.redhat.thermostat.client.core.HostFilter;
-import com.redhat.thermostat.common.ThermostatExtensionRegistry;
-
-class HostFilterRegistry extends ThermostatExtensionRegistry<HostFilter> {
-
-    private static final String FILTER = "(" + Constants.OBJECTCLASS + "=" + HostFilter.class.getName() + ")";
-
-    public HostFilterRegistry(BundleContext context) throws InvalidSyntaxException {
-        super(context, FILTER, HostFilter.class);
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/HostIconDecorator.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +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.internal;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-
-import com.redhat.thermostat.client.core.HostFilter;
-import com.redhat.thermostat.client.osgi.service.HostDecorator;
-import com.redhat.thermostat.client.ui.Decorator;
-import com.redhat.thermostat.client.ui.IconDescriptor;
-import com.redhat.thermostat.client.ui.IconResource;
-import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.common.utils.StreamUtils;
-
-public class HostIconDecorator implements HostDecorator {
-
-    private final HostFilter anyHost = new AnyHostMatcher();
-
-    @Override
-    public Decorator getDecorator() {
-        return new IconDecorator();
-    }
-
-    @Override
-    public HostFilter getFilter() {
-        return anyHost;
-    }
-
-    private static class IconDecorator implements Decorator {
-
-        private final IconDescriptor icon;
-
-        public IconDecorator() {
-            IconDescriptor icon = null;
-            try {
-                InputStream in = new FileInputStream(IconResource.HOST.getPath());
-                icon = new IconDescriptor(ByteBuffer.wrap(StreamUtils.readAll(in)));
-            } catch (IOException ioe) {
-                ioe.printStackTrace();
-            }
-            this.icon = icon;
-        }
-
-        @Override
-        public String getLabel(String originalLabel) {
-            return originalLabel;
-        }
-
-        @Override
-        public IconDescriptor getIconDescriptor() {
-            return icon;
-        }
-
-        @Override
-        public Quadrant getQuadrant() {
-            return Quadrant.MAIN;
-        }
-
-    }
-
-    private static class AnyHostMatcher implements HostFilter {
-        @Override
-        public boolean matches(HostRef toMatch) {
-            return true;
-        }
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/HostTreeDecoratorRegistry.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.internal;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.InvalidSyntaxException;
-
-import com.redhat.thermostat.client.osgi.service.HostDecorator;
-import com.redhat.thermostat.common.ThermostatExtensionRegistry;
-
-class HostTreeDecoratorRegistry extends ThermostatExtensionRegistry<HostDecorator> {
-
-    private static final String FILTER = "(" + Constants.OBJECTCLASS + "=" + HostDecorator.class.getName() + ")";
-
-    public HostTreeDecoratorRegistry(BundleContext context) throws InvalidSyntaxException {
-        super(context, FILTER, HostDecorator.class);
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/Main.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,329 +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.internal;
-
-import java.awt.EventQueue;
-import java.util.concurrent.ExecutorService;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.swing.JOptionPane;
-import javax.swing.JPopupMenu;
-import javax.swing.SwingConstants;
-import javax.swing.SwingUtilities;
-import javax.swing.UIManager;
-import javax.swing.UnsupportedLookAndFeelException;
-
-import com.redhat.swing.laf.dolphin.DolphinLookAndFeel;
-import com.redhat.thermostat.client.core.views.ClientConfigurationView;
-import com.redhat.thermostat.client.internal.config.ConnectionConfiguration;
-import com.redhat.thermostat.client.locale.LocaleResources;
-import com.redhat.thermostat.client.osgi.service.ApplicationService;
-import com.redhat.thermostat.client.ui.ClientConfigurationController;
-import com.redhat.thermostat.client.ui.ClientConfigurationSwing;
-import com.redhat.thermostat.client.ui.MainWindowController;
-import com.redhat.thermostat.client.ui.UiFacadeFactory;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.Constants;
-import com.redhat.thermostat.common.ThreadPoolTimerFactory;
-import com.redhat.thermostat.common.TimerFactory;
-import com.redhat.thermostat.common.appctx.ApplicationContext;
-import com.redhat.thermostat.common.config.ClientPreferences;
-import com.redhat.thermostat.common.config.StartupConfiguration;
-import com.redhat.thermostat.common.dao.DAOFactory;
-import com.redhat.thermostat.common.dao.MongoDAOFactory;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.storage.Connection;
-import com.redhat.thermostat.common.storage.Connection.ConnectionListener;
-import com.redhat.thermostat.common.storage.Connection.ConnectionStatus;
-import com.redhat.thermostat.common.storage.Connection.ConnectionType;
-import com.redhat.thermostat.common.storage.MongoStorageProvider;
-import com.redhat.thermostat.common.storage.StorageProvider;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.utils.keyring.Keyring;
-
-public class Main {
-    
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private static final Logger logger = LoggingUtils.getLogger(Main.class);
-
-    private OSGIUtils serviceProvider;
-    private UiFacadeFactory uiFacadeFactory;
-    private DAOFactory daoFactory;
-    
-    public Main(Keyring keyring, UiFacadeFactory uiFacadeFactory, String[] args) {
-        ClientPreferences prefs = new ClientPreferences(keyring);
-        StartupConfiguration config = new ConnectionConfiguration(prefs);
-        StorageProvider connProv = new MongoStorageProvider(config);
-
-        DAOFactory daoFactory = new MongoDAOFactory(connProv);
-        TimerFactory timerFactory = new ThreadPoolTimerFactory(1);
-
-        init(OSGIUtils.getInstance(), uiFacadeFactory, daoFactory, timerFactory);
-    }
-
-    Main(OSGIUtils serviceProvider, UiFacadeFactory uiFacadeFactory, DAOFactory daoFactory, TimerFactory timerFactory) {
-        init(serviceProvider, uiFacadeFactory, daoFactory, timerFactory);
-    }
-
-    private void init(OSGIUtils serviceProvider, UiFacadeFactory uiFacadeFactory, DAOFactory daoFactory, TimerFactory timerFactory) {
-        this.serviceProvider = serviceProvider;
-        this.uiFacadeFactory = uiFacadeFactory;
-        this.daoFactory = daoFactory;
-        ApplicationContext.getInstance().setTimerFactory(timerFactory);
-    }
-
-    public void run() {
-        EventQueue.invokeLater(new Runnable() {
-
-            @Override
-            public void run() {
-
-                // check if the user has other preferences...
-                // not that there is any reason!
-                String laf = System.getProperty("swing.defaultlaf");
-                if (laf == null) {
-                    try {
-                        UIManager.setLookAndFeel(new DolphinLookAndFeel());
-                    } catch (UnsupportedLookAndFeelException e) {
-                        logger.log(Level.WARNING, "cannot use DolphinLookAndFeel");
-                    }
-                }
-
-                // TODO: move them in an appropriate place
-                JPopupMenu.setDefaultLightWeightPopupEnabled(false);
-                UIManager.getDefaults().put("OptionPane.buttonOrientation", SwingConstants.RIGHT);
-                UIManager.getDefaults().put("OptionPane.isYesLast", true);
-                UIManager.getDefaults().put("OptionPane.sameSizeButtons", true);
-                
-                showGui();
-            }
-
-        });
-
-        try {
-            uiFacadeFactory.awaitShutdown();
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-        }
-    }
-
-    private void showGui() {
-        ApplicationService appSrv = serviceProvider.getService(ApplicationService.class);
-        final ExecutorService service = appSrv.getApplicationExecutor();
-        service.execute(new ConnectorSetup(service));
-    }
-    
-    private class ConnectorSetup implements Runnable {
-        
-        private ExecutorService service;
-        public ConnectorSetup(ExecutorService service) {
-            this.service = service;
-        }
-        
-        @Override
-        public void run() {
-            
-            Connection connection = daoFactory.getConnection();
-            connection.setType(ConnectionType.LOCAL);
-            ConnectionListener connectionListener = new ConnectionHandler(connection, service);
-            connection.addListener(connectionListener);
-            try {
-                connection.connect();
-            } catch (Throwable t) {
-                logger.log(Level.WARNING, "connection attempt failed: ", t);
-            }
-        }
-    }
-    
-    private class Connector implements Runnable {
-        private Connection connection;
-        Connector(Connection connection) {
-            this.connection = connection;
-        }
-        
-        @Override
-        public void run() {
-            try {
-                connection.connect();
-            } catch (Throwable t) {
-                logger.log(Level.WARNING, "connection attempt failed: ", t);
-            }
-        }
-    }
-    
-    private class ConnectionAttemp implements Runnable {
-        private Connection connection;
-        private ExecutorService service;
-        public ConnectionAttemp(Connection connection, ExecutorService service) {
-            this.connection = connection;
-            this.service = service;
-        }
-        
-        @Override
-        public void run() {
-            Object[] options = {
-                    translator.localize(LocaleResources.CONNECTION_WIZARD),
-                    translator.localize(LocaleResources.CONNECTION_QUIT),
-            };
-            int n = JOptionPane
-                    .showOptionDialog(
-                            null,
-                            translator.localize(LocaleResources.CONNECTION_FAILED_TO_CONNECT_DESCRIPTION),
-                            translator.localize(LocaleResources.CONNECTION_FAILED_TO_CONNECT_TITLE),
-                            JOptionPane.OK_CANCEL_OPTION,
-                            JOptionPane.ERROR_MESSAGE, null, options,
-                            options[0]);
-
-            switch (n) {
-
-            case JOptionPane.CANCEL_OPTION:
-            case JOptionPane.CLOSED_OPTION:
-            case JOptionPane.NO_OPTION:
-                uiFacadeFactory
-                        .shutdown(Constants.EXIT_UNABLE_TO_CONNECT_TO_DATABASE);
-                break;
-
-            case JOptionPane.YES_OPTION:
-            default:
-                createPreferencesDialog(connection, service);
-                break;
-            }
-        }
-    }
-    
-    private void connect(Connection connection, ExecutorService service) {
-        service.execute(new Connector(connection));
-    }
-    
-    private class ConfigDialogListener implements ActionListener<ClientConfigurationView.Action> {
-        private Connection connection;
-        private ExecutorService service;
-        public ConfigDialogListener(Connection connection, ExecutorService service) {
-            this.connection = connection;
-            this.service = service;
-        }
-        
-        @Override
-        public void actionPerformed(ActionEvent<ClientConfigurationView.Action> actionEvent) {
-            switch (actionEvent.getActionId()) {
-            case CLOSE_CANCEL:
-                uiFacadeFactory.shutdown(Constants.EXIT_UNABLE_TO_CONNECT_TO_DATABASE);
-                break;
-            
-            case CLOSE_ACCEPT:
-            default:
-                connect(connection, service);
-                break;
-            }
-        }
-    }
-    
-    private void createPreferencesDialog(final Connection connection, final ExecutorService service) {
-
-        ClientPreferences prefs = new ClientPreferences(OSGIUtils.getInstance().getService(Keyring.class));
-        ClientConfigurationView configDialog = new ClientConfigurationSwing();
-        ClientConfigurationController controller =
-                new ClientConfigurationController(prefs, configDialog);
-        
-        configDialog.addListener(new ConfigDialogListener(connection, service));
-        controller.showDialog();
-    }
-    
-    private class ConnectionHandler implements ConnectionListener {
-        private boolean retry;
-        private Connection connection;
-        private ExecutorService service;
-        public ConnectionHandler(Connection connection, ExecutorService service) {
-            this.connection = connection;
-            this.retry = true;
-            this.service = service;
-        }
-        
-        private void showConnectionAttemptWarning() {
-            SwingUtilities.invokeLater(new ConnectionAttemp(connection, service));
-        }
-        
-        @Override
-        public void changed(ConnectionStatus newStatus) {
-            if (newStatus == ConnectionStatus.CONNECTED) {
-                
-                // register the storage, so other services can request it
-                daoFactory.registerDAOsAndStorageAsOSGiServices();
-                uiFacadeFactory.setHostInfoDao(daoFactory.getHostInfoDAO());
-                uiFacadeFactory.setCpuStatDao(daoFactory.getCpuStatDAO());
-                uiFacadeFactory.setMemoryStatDao(daoFactory.getMemoryStatDAO());
-                uiFacadeFactory.setNetworkInfoDao(daoFactory.getNetworkInterfaceInfoDAO());
-
-                uiFacadeFactory.setVmInfoDao(daoFactory.getVmInfoDAO());
-                uiFacadeFactory.setVmCpuStatDao(daoFactory.getVmCpuStatDAO());
-                uiFacadeFactory.setVmMemoryStatDao(daoFactory.getVmMemoryStatDAO());
-                uiFacadeFactory.setVmGcStatDao(daoFactory.getVmGcStatDAO());
-
-                showMainWindow();
-            } else if (newStatus == ConnectionStatus.FAILED_TO_CONNECT) {
-                if (retry) {
-                    retry = false;
-                    showConnectionAttemptWarning();
-                } else {
-                    JOptionPane.showMessageDialog(
-                            null,
-                            translator.localize(LocaleResources.CONNECTION_FAILED_TO_CONNECT_DESCRIPTION),
-                            translator.localize(LocaleResources.CONNECTION_FAILED_TO_CONNECT_TITLE),
-                            JOptionPane.ERROR_MESSAGE);
-                    uiFacadeFactory.shutdown(Constants.EXIT_UNABLE_TO_CONNECT_TO_DATABASE);
-                }
-            }
-        }
-    }
-
-
-    private void showMainWindow() {
-        SwingUtilities.invokeLater(new ShowMainWindow());
-    }
-    
-    private class ShowMainWindow implements Runnable {
-        @Override
-        public void run() {
-            MainWindowController mainController = uiFacadeFactory.getMainWindow();
-            mainController.showMainMainWindow();                        
-        }
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/MainView.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.internal;
-
-import java.awt.event.MouseEvent;
-import java.util.List;
-
-import com.redhat.thermostat.client.core.HostFilter;
-import com.redhat.thermostat.client.core.VmFilter;
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.osgi.service.HostDecorator;
-import com.redhat.thermostat.client.osgi.service.MenuAction;
-import com.redhat.thermostat.client.osgi.service.VmDecorator;
-import com.redhat.thermostat.client.osgi.service.VMContextAction;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.HostsVMsLoader;
-import com.redhat.thermostat.common.dao.Ref;
-
-public interface MainView {
-
-    enum Action {
-        VISIBLE,
-        HIDDEN,
-        HOST_VM_TREE_FILTER,
-        HOST_VM_SELECTION_CHANGED,
-        SHOW_AGENT_CONFIG,
-        SHOW_CLIENT_CONFIG,
-        SWITCH_HISTORY_MODE,
-        SHOW_ABOUT_DIALOG,
-        SHUTDOWN,
-        SHOW_VM_CONTEXT_MENU,
-        VM_CONTEXT_ACTION,
-    }
-
-    void addActionListener(ActionListener<Action> capture);
-
-    void updateTree(List<HostFilter> hostFilters, List<VmFilter> vmFilters,
-            List<HostDecorator> hostDecorators, List<VmDecorator> vmDecorators,
-            HostsVMsLoader any);
-
-    String getHostVmTreeFilterText();
-    
-    void setWindowTitle(String title);
-
-    void showMainWindow();
-
-    void hideMainWindow();
-
-    Ref getSelectedHostOrVm();
-
-    void setSubView(BasicView view);
-
-    void setStatusBarPrimaryStatus(String primaryStatus);
-    
-    /**
-     * Adds a menu item to the window. Assumes the menu path is valid (has a
-     * non-zero length) and doesn't collide with existing menus.
-     */
-    void addMenu(MenuAction action);
-
-    /**
-     * Removes a menu item to the window. Assumes the menu path is valid (has a
-     * non-zero length) and doesn't collide with existing menus.
-     */
-    void removeMenu(MenuAction action);
-
-    void showVMContextActions(List<VMContextAction> actions, MouseEvent e);
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/MainWindowControllerImpl.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,512 +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.internal;
-
-import java.awt.event.MouseEvent;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import org.osgi.framework.InvalidSyntaxException;
-
-import com.redhat.thermostat.client.core.HostFilter;
-import com.redhat.thermostat.client.core.VmFilter;
-import com.redhat.thermostat.client.core.views.AgentInformationDisplayView;
-import com.redhat.thermostat.client.core.views.AgentInformationViewProvider;
-import com.redhat.thermostat.client.core.views.ClientConfigViewProvider;
-import com.redhat.thermostat.client.core.views.ClientConfigurationView;
-import com.redhat.thermostat.client.internal.MainView.Action;
-import com.redhat.thermostat.client.internal.ui.swing.AboutDialog;
-import com.redhat.thermostat.client.osgi.service.HostDecorator;
-import com.redhat.thermostat.client.osgi.service.MenuAction;
-import com.redhat.thermostat.client.osgi.service.VMContextAction;
-import com.redhat.thermostat.client.osgi.service.VmDecorator;
-import com.redhat.thermostat.client.ui.AgentInformationDisplayController;
-import com.redhat.thermostat.client.ui.AgentInformationDisplayModel;
-import com.redhat.thermostat.client.ui.ClientConfigurationController;
-import com.redhat.thermostat.client.ui.HostInformationController;
-import com.redhat.thermostat.client.ui.HostVmFilter;
-import com.redhat.thermostat.client.ui.MainWindowController;
-import com.redhat.thermostat.client.ui.SummaryController;
-import com.redhat.thermostat.client.ui.UiFacadeFactory;
-import com.redhat.thermostat.client.ui.VmInformationController;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.ApplicationInfo;
-import com.redhat.thermostat.common.DefaultHostsVMsLoader;
-import com.redhat.thermostat.common.HostsVMsLoader;
-import com.redhat.thermostat.common.ThermostatExtensionRegistry;
-import com.redhat.thermostat.common.Timer;
-import com.redhat.thermostat.common.Timer.SchedulingType;
-import com.redhat.thermostat.common.appctx.ApplicationContext;
-import com.redhat.thermostat.common.config.ClientPreferences;
-import com.redhat.thermostat.common.dao.HostInfoDAO;
-import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.common.dao.Ref;
-import com.redhat.thermostat.common.dao.VmInfoDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.utils.keyring.Keyring;
-
-public class MainWindowControllerImpl implements MainWindowController {
-
-    private static final Logger logger = LoggingUtils.getLogger(MainWindowControllerImpl.class);
-
-    private final CopyOnWriteArrayList<HostFilter> hostFilters = new CopyOnWriteArrayList<>();
-    private final CopyOnWriteArrayList<VmFilter> vmFilters = new CopyOnWriteArrayList<>();
-
-    private final CopyOnWriteArrayList<HostDecorator> hostTreeDecorators = new CopyOnWriteArrayList<>();
-    private final CopyOnWriteArrayList<VmDecorator> vmTreeDecorators = new CopyOnWriteArrayList<>();
-
-    private Timer backgroundUpdater;
-
-    private MainView view;
-
-    private final HostInfoDAO hostsDAO;
-    private final VmInfoDAO vmsDAO;
-
-    private ApplicationInfo appInfo;
-
-    private UiFacadeFactory facadeFactory;
-
-    private MenuRegistry menuRegistry;
-    private ActionListener<ThermostatExtensionRegistry.Action> menuListener =
-            new ActionListener<ThermostatExtensionRegistry.Action>()
-    {
-        @Override
-        public void actionPerformed(
-            ActionEvent<ThermostatExtensionRegistry.Action> actionEvent) {
-            MenuAction action = (MenuAction) actionEvent.getPayload();
-
-            switch (actionEvent.getActionId()) {
-            case SERVICE_ADDED:
-                view.addMenu(action);
-                break;
-
-            case SERVICE_REMOVED:
-                view.removeMenu(action);
-                break;
-
-            default:
-                logger.log(Level.WARNING, "received unknown event from MenuRegistry: " +
-                                           actionEvent.getActionId());
-                break;
-            }
-        }
-    };
-
-    private HostVmFilter searchFilter;
-    private VmFilterRegistry vmFilterRegistry;
-    private HostFilterRegistry hostFilterRegistry;
-
-    private ActionListener<ThermostatExtensionRegistry.Action> hostFilterListener = new UpdateListAndTree<>(HostFilter.class, hostFilters);
-    private ActionListener<ThermostatExtensionRegistry.Action> vmFilterListener = new UpdateListAndTree<>(VmFilter.class, vmFilters);
-
-    private HostTreeDecoratorRegistry hostDecoratorRegistry;
-    private VMTreeDecoratorRegistry vmDecoratorRegistry;
-
-    private ActionListener<ThermostatExtensionRegistry.Action> hostDecoratorListener = new UpdateListAndTree<>(HostDecorator.class, hostTreeDecorators);
-    private ActionListener<ThermostatExtensionRegistry.Action> vmDecoratorListener = new UpdateListAndTree<>(VmDecorator.class, vmTreeDecorators);
-
-    private VMInformationRegistry vmInfoRegistry;
-    private ActionListener<ThermostatExtensionRegistry.Action> vmInfoRegistryListener =
-            new ActionListener<ThermostatExtensionRegistry.Action> ()
-    {
-        public void actionPerformed(com.redhat.thermostat.common.ActionEvent<ThermostatExtensionRegistry.Action>
-                                    actionEvent)
-        {
-            updateView();
-        };
-    };
-            
-    private boolean showHistory;
-
-    private VmInformationControllerProvider vmInfoControllerProvider;
-
-    public MainWindowControllerImpl(UiFacadeFactory facadeFactory, MainView view, RegistryFactory registryFactory, HostInfoDAO hostsDao, VmInfoDAO vmsDAO)
-    {
-        try {
-            vmFilterRegistry = registryFactory.createVmFilterRegistry();
-            hostFilterRegistry = registryFactory.createHostFilterRegistry();
-            hostDecoratorRegistry = registryFactory.createHostTreeDecoratorRegistry();
-            vmDecoratorRegistry = registryFactory.createVMTreeDecoratorRegistry();
-            menuRegistry = registryFactory.createMenuRegistry();
-            vmInfoRegistry = registryFactory.createVMInformationRegistry();
-            
-        } catch (InvalidSyntaxException e) {
-            throw new RuntimeException(e);
-        }
-
-        searchFilter = new HostVmFilter();
-        hostFilters.add(searchFilter);
-        vmFilters.add(searchFilter);
-        
-        this.facadeFactory = facadeFactory;
-
-        this.hostsDAO = hostsDao;
-        this.vmsDAO = vmsDAO;
-
-        initView(view);
-
-        vmInfoControllerProvider = new VmInformationControllerProvider();
-
-        appInfo = new ApplicationInfo();
-        view.setWindowTitle(appInfo.getName());
-        initializeTimer();
-
-        updateView();
-
-        installListenersAndStartRegistries();
-    }
-
-    /**
-     * This method is for testing purposes only
-     */
-    HostVmFilter getSearchFilter() {
-        return searchFilter;
-    }
-    
-    /**
-     * This method is for testing purposes only
-     */ 
-    List<VmDecorator> getVmTreeDecorators() {
-        return vmTreeDecorators;
-    }
-    
-    /**
-     * This method is for testing purposes only
-     */
-    ActionListener<ThermostatExtensionRegistry.Action> getMenuListener() {
-        return menuListener;
-    }
-    
-    private void initializeTimer() {
-        ApplicationContext ctx = ApplicationContext.getInstance();
-        backgroundUpdater = ctx.getTimerFactory().createTimer();
-        backgroundUpdater.setAction(new Runnable() {
-            @Override
-            public void run() {
-                doUpdateTreeAsync();
-            }
-        });
-        backgroundUpdater.setInitialDelay(0);
-        backgroundUpdater.setDelay(3);
-        backgroundUpdater.setTimeUnit(TimeUnit.SECONDS);
-        backgroundUpdater.setSchedulingType(SchedulingType.FIXED_RATE);
-    }
-
-    private void startBackgroundUpdates() {
-        backgroundUpdater.start();
-    }
-
-    public void stopBackgroundUpdates() {
-        backgroundUpdater.stop();
-    }
-
-    @Override
-    public void setHostVmTreeFilter(String filter) {
-        this.searchFilter.setFilter(filter);
-        doUpdateTreeAsync();
-    }
-
-    public void doUpdateTreeAsync() {
-        HostsVMsLoader loader = new DefaultHostsVMsLoader(hostsDAO, vmsDAO, !showHistory);
-        view.updateTree(hostFilters, vmFilters, hostTreeDecorators, vmTreeDecorators, loader);
-    }
-
-    private void initView(MainView mainView) {
-        this.view = mainView;
-        mainView.addActionListener(new ActionListener<MainView.Action>() {
-
-            @Override
-            public void actionPerformed(ActionEvent<MainView.Action> evt) {
-                MainView.Action action = evt.getActionId();
-                switch (action) {
-                case VISIBLE:
-                    startBackgroundUpdates();
-                    break;
-                case HIDDEN:
-                    stopBackgroundUpdates();
-                    break;
-                case HOST_VM_SELECTION_CHANGED:
-                    updateView();
-                    break;
-                case HOST_VM_TREE_FILTER:
-                    String filter = view.getHostVmTreeFilterText();
-                    setHostVmTreeFilter(filter);
-                    break;
-                case SHOW_AGENT_CONFIG:
-                    showAgentConfiguration();
-                    break;
-                case SHOW_CLIENT_CONFIG:
-                    showConfigureClientPreferences();
-                    break;
-                case SWITCH_HISTORY_MODE:
-                    switchHistoryMode();
-                    break;
-                case SHOW_ABOUT_DIALOG:
-                    showAboutDialog();
-                    break;
-                case SHOW_VM_CONTEXT_MENU:
-                    showContextMenu(evt);
-                    break;
-                case VM_CONTEXT_ACTION:
-                    handleVMHooks(evt);
-                    break;
-                case SHUTDOWN:
-                    shutdownApplication();
-                    break;
-                default:
-                    throw new IllegalStateException("unhandled action");
-                }
-            }
-
-        });
-    }
-
-    private void shutdownApplication() {
-        uninstallListenersAndStopRegistries();
-
-        view.hideMainWindow();
-        ApplicationContext.getInstance().getTimerFactory().shutdown();
-        shutdownOSGiFramework();
-    }
-
-    private void installListenersAndStartRegistries() {
-        menuRegistry.addActionListener(menuListener);
-        menuRegistry.start();
-
-        hostFilterRegistry.addActionListener(hostFilterListener);
-        hostFilterRegistry.start();
-
-        vmFilterRegistry.addActionListener(vmFilterListener);
-        vmFilterRegistry.start();
-
-        hostDecoratorRegistry.addActionListener(hostDecoratorListener);
-        hostDecoratorRegistry.start();
-
-        vmDecoratorRegistry.addActionListener(vmDecoratorListener);
-        vmDecoratorRegistry.start();
-
-        vmInfoRegistry.addActionListener(vmInfoRegistryListener);
-        vmInfoRegistry.start();
-    }
-
-    private void uninstallListenersAndStopRegistries() {
-        menuRegistry.removeActionListener(menuListener);
-        menuListener = null;
-        menuRegistry.stop();
-
-        hostFilterRegistry.removeActionListener(hostFilterListener);
-        hostFilterListener = null;
-        hostFilterRegistry.stop();
-
-        vmFilterRegistry.removeActionListener(vmFilterListener);
-        vmFilterListener = null;
-        vmFilterRegistry.stop();
-
-        hostDecoratorRegistry.removeActionListener(hostDecoratorListener);
-        hostDecoratorListener = null;
-        hostDecoratorRegistry.stop();
-
-        vmDecoratorRegistry.removeActionListener(vmDecoratorListener);
-        vmDecoratorListener = null;
-        vmDecoratorRegistry.stop();
-
-        vmInfoRegistry.removeActionListener(vmInfoRegistryListener);
-        vmInfoRegistryListener = null;
-        vmInfoRegistry.stop();
-    }
-
-    private void shutdownOSGiFramework() {
-        facadeFactory.shutdown();
-    }
-
-    private void showContextMenu(ActionEvent<Action> evt) {
-        List<VMContextAction> toShow = new ArrayList<>();
-        VmRef vm = (VmRef) view.getSelectedHostOrVm();
-
-        logger.log(Level.INFO, "registering applicable VMContextActions actions to show");
-
-        for (VMContextAction action : facadeFactory.getVMContextActions()) {
-            if (action.getFilter().matches(vm)) {
-                toShow.add(action);
-            }
-        }
-
-        view.showVMContextActions(toShow, (MouseEvent)evt.getPayload());
-    }
-
-    private void handleVMHooks(ActionEvent<MainView.Action> event) {
-        Object payload = event.getPayload();
-        if (payload instanceof VMContextAction) { 
-            try {
-                VMContextAction action = (VMContextAction) payload;
-                action.execute((VmRef) view.getSelectedHostOrVm());
-            } catch (Throwable error) {
-                logger.log(Level.SEVERE, "");
-            }
-        }
-    }
-    
-    @Override
-    public void showMainMainWindow() {
-        view.showMainWindow();
-    }
-
-    private void showAboutDialog() {
-        AboutDialog aboutDialog = new AboutDialog(appInfo);
-        aboutDialog.setModal(true);
-        aboutDialog.pack();
-        aboutDialog.setVisible(true);
-    }
-
-    private void showAgentConfiguration() {
-        AgentInformationDisplayModel model = new AgentInformationDisplayModel();
-        AgentInformationViewProvider viewProvider = OSGIUtils.getInstance().getService(AgentInformationViewProvider.class);
-        AgentInformationDisplayView view = viewProvider.createView();
-        AgentInformationDisplayController controller = new AgentInformationDisplayController(model, view);
-        controller.showView();
-    }
-
-    private void showConfigureClientPreferences() {
-        ClientPreferences prefs = new ClientPreferences(OSGIUtils.getInstance().getService(Keyring.class));
-        ClientConfigViewProvider viewProvider = OSGIUtils.getInstance().getService(ClientConfigViewProvider.class);
-        ClientConfigurationView view = viewProvider.createView();
-        ClientConfigurationController controller = new ClientConfigurationController(prefs, view);
-        controller.showDialog();
-    }
-
-    private void switchHistoryMode() {
-        showHistory = !showHistory;
-        doUpdateTreeAsync();
-    }
-
-    private void updateView() {
-        // this is quite an ugly method. there must be a cleaner way to do this
-        Ref ref = view.getSelectedHostOrVm();
-
-        if (ref == null) {
-            SummaryController controller = facadeFactory.getSummary();
-            view.setSubView(controller.getView());
-        } else if (ref instanceof HostRef) {
-            HostRef hostRef = (HostRef) ref;
-            HostInformationController hostController = facadeFactory.getHostController(hostRef);
-            view.setSubView(hostController.getView());
-            view.setStatusBarPrimaryStatus("host: " + hostRef.getHostName() + ", id: " + hostRef.getAgentId());
-        } else if (ref instanceof VmRef) {
-            VmRef vmRef = (VmRef) ref;
-            VmInformationController vmInformation =
-                    vmInfoControllerProvider.getVmInfoController(vmRef);
-            view.setSubView(vmInformation.getView());
-            view.setStatusBarPrimaryStatus("vm: " + vmRef.getName() + ", pid: " + vmRef.getStringID() +
-                                           ", host: " + vmRef.getAgent().getHostName());
-        } else {
-            throw new IllegalArgumentException("unknown type of ref");
-        }
-    }
-
-    private class UpdateListAndTree<T> implements ActionListener<ThermostatExtensionRegistry.Action> {
-
-        private final Class<T> extensionClass;
-        private final CopyOnWriteArrayList<T> extensionList;
-
-        public UpdateListAndTree(Class<T> extensionClass, CopyOnWriteArrayList<T> addRemoveExtensionsFrom) {
-            this.extensionClass = extensionClass;
-            this.extensionList = addRemoveExtensionsFrom;
-        }
-
-        @SuppressWarnings("unchecked")
-        @Override
-        public void actionPerformed(ActionEvent<com.redhat.thermostat.common.ThermostatExtensionRegistry.Action> actionEvent) {
-
-            Object payload = actionEvent.getPayload();
-            if (!extensionClass.isInstance(payload)) {
-                throw new IllegalArgumentException("unexpected payload type. expected a " + extensionClass.getName() + " but got " + payload.getClass().getName());
-            }
-
-            T filter = (T) payload;
-
-            switch (actionEvent.getActionId()) {
-            case SERVICE_ADDED:
-                extensionList.add(filter);
-                doUpdateTreeAsync();
-                break;
-
-            case SERVICE_REMOVED:
-                extensionList.remove(filter);
-                doUpdateTreeAsync();
-                break;
-
-            default:
-                logger.log(Level.WARNING, "received unknown event from ExtensionRegistry: " +
-                                           actionEvent.getActionId());
-                break;
-            }
-        }
-    }
-
-    private class VmInformationControllerProvider {
-        private VmInformationController lastSelectedVM;
-        private Map<VmRef, Integer> selectedForVM = new ConcurrentHashMap<>();
-        
-        VmInformationController getVmInfoController(VmRef vmRef) {
-            int id = 0;
-            if (lastSelectedVM != null) {
-                id = lastSelectedVM.getSelectedChildID();
-            }
-            
-            lastSelectedVM = facadeFactory.getVmController(vmRef);
-            if (!lastSelectedVM.selectChildID(id)) {
-                Integer _id = selectedForVM.get(vmRef);
-                id = _id != null? _id : 0;
-                lastSelectedVM.selectChildID(id);
-            }
-
-            selectedForVM.put(vmRef, id);
-            
-            return lastSelectedVM;
-        }
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/MenuRegistry.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.internal;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.InvalidSyntaxException;
-
-import com.redhat.thermostat.client.osgi.service.MenuAction;
-import com.redhat.thermostat.common.ThermostatExtensionRegistry;
-
-public class MenuRegistry extends ThermostatExtensionRegistry<MenuAction> {
-
-    private static final String FILTER = "(" + Constants.OBJECTCLASS + "=" + MenuAction.class.getName() + ")";
-
-    public MenuRegistry(BundleContext context) throws InvalidSyntaxException {
-    	super(context, FILTER, MenuAction.class);
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/RegistryFactory.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.internal;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.InvalidSyntaxException;
-
-class RegistryFactory {
-
-    private BundleContext context;
-    RegistryFactory(BundleContext context) {
-        this.context = context;
-    }
-
-    HostTreeDecoratorRegistry createHostTreeDecoratorRegistry() throws InvalidSyntaxException {
-        return new HostTreeDecoratorRegistry(context);
-    }
-    
-    VMTreeDecoratorRegistry createVMTreeDecoratorRegistry() throws InvalidSyntaxException {
-        return new VMTreeDecoratorRegistry(context);
-    }
-    
-    HostFilterRegistry createHostFilterRegistry() throws InvalidSyntaxException {
-        return new HostFilterRegistry(context);
-    }
-
-    VmFilterRegistry createVmFilterRegistry() throws InvalidSyntaxException {
-        return new VmFilterRegistry(context);
-    }
-    
-    MenuRegistry createMenuRegistry() throws InvalidSyntaxException {
-        return new MenuRegistry(context);
-    }
-    
-    VMInformationRegistry createVMInformationRegistry() throws InvalidSyntaxException {
-        return new VMInformationRegistry(context);
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/UiFacadeFactoryImpl.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,199 +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.internal;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.concurrent.CountDownLatch;
-
-import org.osgi.framework.BundleContext;
-
-import com.redhat.thermostat.client.core.VmInformationService;
-import com.redhat.thermostat.client.core.views.HostInformationViewProvider;
-import com.redhat.thermostat.client.core.views.SummaryViewProvider;
-import com.redhat.thermostat.client.core.views.VmInformationViewProvider;
-import com.redhat.thermostat.client.osgi.service.VMContextAction;
-import com.redhat.thermostat.client.ui.HostInformationController;
-import com.redhat.thermostat.client.ui.MainWindow;
-import com.redhat.thermostat.client.ui.MainWindowController;
-import com.redhat.thermostat.client.ui.SummaryController;
-import com.redhat.thermostat.client.ui.UiFacadeFactory;
-import com.redhat.thermostat.client.ui.VmInformationController;
-import com.redhat.thermostat.common.dao.CpuStatDAO;
-import com.redhat.thermostat.common.dao.HostInfoDAO;
-import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.common.dao.MemoryStatDAO;
-import com.redhat.thermostat.common.dao.NetworkInterfaceInfoDAO;
-import com.redhat.thermostat.common.dao.VmCpuStatDAO;
-import com.redhat.thermostat.common.dao.VmGcStatDAO;
-import com.redhat.thermostat.common.dao.VmInfoDAO;
-import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-
-public class UiFacadeFactoryImpl implements UiFacadeFactory {
-
-    private CountDownLatch shutdown = new CountDownLatch(1);
-
-    private Collection<VmInformationService> vmInformationServices = new ArrayList<>();
-    private Collection<VMContextAction> contextAction = new ArrayList<>();
-
-    private BundleContext context;
-
-    private HostInfoDAO hostInfoDao;
-    private CpuStatDAO cpuStatDao;
-    private MemoryStatDAO memoryStatDao;
-    private NetworkInterfaceInfoDAO networkInfoDao;
-
-    private VmInfoDAO vmInfoDao;
-    private VmCpuStatDAO vmCpuStatDao;
-    private VmMemoryStatDAO vmMemoryStatDao;
-    private VmGcStatDAO vmGcStatDao;
-
-    private OSGIUtils serviceProvider;
-    
-    UiFacadeFactoryImpl(OSGIUtils serviceProvider, BundleContext context) {
-        this.context = context;
-        this.serviceProvider = serviceProvider;
-    }
-    
-    public UiFacadeFactoryImpl(BundleContext context) {
-        this(OSGIUtils.getInstance(), context);
-    }
-
-    @Override
-    public void setHostInfoDao(HostInfoDAO hostInfoDao) {
-        this.hostInfoDao = hostInfoDao;
-    }
-
-    public void setCpuStatDao(CpuStatDAO cpuStatDao) {
-        this.cpuStatDao = cpuStatDao;
-    }
-
-    public void setMemoryStatDao(MemoryStatDAO memoryStatDao) {
-        this.memoryStatDao = memoryStatDao;
-    }
-
-    public void setNetworkInfoDao(NetworkInterfaceInfoDAO networkInfoDao) {
-        this.networkInfoDao = networkInfoDao;
-    }
-
-    public void setVmInfoDao(VmInfoDAO vmInfoDao) {
-        this.vmInfoDao = vmInfoDao;
-    }
-
-    public void setVmCpuStatDao(VmCpuStatDAO vmCpuStatDao) {
-        this.vmCpuStatDao = vmCpuStatDao;
-    }
-
-    @Override
-    public void setVmMemoryStatDao(VmMemoryStatDAO vmMemoryStatDao) {
-        this.vmMemoryStatDao = vmMemoryStatDao;
-    }
-
-    @Override
-    public void setVmGcStatDao(VmGcStatDAO vmGcStatDao) {
-        this.vmGcStatDao = vmGcStatDao;
-    }
-
-    @Override
-    public MainWindowController getMainWindow() {
-        MainView mainView = new MainWindow();
-        RegistryFactory registryFactory = new RegistryFactory(context);
-        return new MainWindowControllerImpl(this, mainView, registryFactory, hostInfoDao, vmInfoDao);
-    }
-
-    @Override
-    public SummaryController getSummary() {
-        SummaryViewProvider viewProvider = serviceProvider.getService(SummaryViewProvider.class);
-        return new SummaryController(hostInfoDao, vmInfoDao, viewProvider);
-    }
-
-    @Override
-    public HostInformationController getHostController(HostRef ref) {
-        HostInformationViewProvider viewProvider = serviceProvider.getService(HostInformationViewProvider.class);
-        return new HostInformationController(hostInfoDao, networkInfoDao, cpuStatDao, memoryStatDao, ref, viewProvider);
-    }
-
-    @Override
-    public VmInformationController getVmController(VmRef ref) {
-        VmInformationViewProvider viewProvider = serviceProvider.getService(VmInformationViewProvider.class);
-        return new VmInformationController(this, vmInfoDao, vmCpuStatDao, vmMemoryStatDao, vmGcStatDao, ref, viewProvider);
-    }
-
-    @Override
-    public Collection<VmInformationService> getVmInformationServices() {
-        return vmInformationServices;
-    }
-
-    @Override
-    public void addVmInformationService(VmInformationService vmInfoService) {
-        vmInformationServices.add(vmInfoService);
-    }
-
-    @Override
-    public void removeVmInformationService(VmInformationService vmInfoService) {
-        vmInformationServices.remove(vmInfoService);
-    }
-
-    @Override
-    public Collection<VMContextAction> getVMContextActions() {
-        return contextAction;
-    }
-
-    @Override
-    public void addVMContextAction(VMContextAction service) {
-        contextAction.add(service);
-    }
-
-    @Override
-    public void shutdown() {
-        shutdown.countDown();
-    }
-
-    @Override
-    public void shutdown(int exitCode) {
-        // TODO implement returning exit codes
-        shutdown();
-    }
-
-    @Override
-    public void awaitShutdown() throws InterruptedException {
-        shutdown.await();
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/VMInformationRegistry.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.internal;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.InvalidSyntaxException;
-
-import com.redhat.thermostat.client.core.VmInformationService;
-import com.redhat.thermostat.common.ThermostatExtensionRegistry;
-
-class VMInformationRegistry extends ThermostatExtensionRegistry<VmInformationService> {
-
-    private static final String FILTER = "(&(" + Constants.OBJECTCLASS + "=" + VmInformationService.class.getName() + "))";
-    
-    public VMInformationRegistry(BundleContext context) throws InvalidSyntaxException {
-        super(context, FILTER, VmInformationService.class);
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/VMTreeDecoratorRegistry.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.internal;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.InvalidSyntaxException;
-
-import com.redhat.thermostat.client.osgi.service.VmDecorator;
-import com.redhat.thermostat.common.ThermostatExtensionRegistry;
-
-class VMTreeDecoratorRegistry extends ThermostatExtensionRegistry<VmDecorator> {
-
-    private static final String FILTER = "(" + Constants.OBJECTCLASS + "=" + VmDecorator.class.getName() + ")";
-    
-    public VMTreeDecoratorRegistry(BundleContext context) throws InvalidSyntaxException {
-        super(context, FILTER, VmDecorator.class);
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/VmFilterRegistry.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.internal;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.InvalidSyntaxException;
-
-import com.redhat.thermostat.client.core.VmFilter;
-import com.redhat.thermostat.common.ThermostatExtensionRegistry;
-
-class VmFilterRegistry extends ThermostatExtensionRegistry<VmFilter> {
-
-    private static final String FILTER = "(" + Constants.OBJECTCLASS + "=" + VmFilter.class.getName() + ")";
-
-    public VmFilterRegistry(BundleContext context) throws InvalidSyntaxException {
-        super(context, FILTER, VmFilter.class);
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/config/ConnectionConfiguration.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.internal.config;
-
-import com.redhat.thermostat.common.cli.AuthenticationConfiguration;
-import com.redhat.thermostat.common.config.ClientPreferences;
-import com.redhat.thermostat.common.config.StartupConfiguration;
-
-public class ConnectionConfiguration implements StartupConfiguration, AuthenticationConfiguration {
-
-    private final ClientPreferences clientPrefs;
-
-    public ConnectionConfiguration(ClientPreferences clientPrefs) {
-        this.clientPrefs = clientPrefs;
-    }
-
-    @Override
-    public String getDBConnectionString() {
-        return clientPrefs.getConnectionUrl();
-    }
-    
-    @Override
-    public String getPassword() {
-        return clientPrefs.getPassword();
-    }
-    
-    @Override
-    public String getUsername() {
-        return clientPrefs.getUserName();
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/osgi/ApplicationServiceProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.internal.osgi;
-
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import com.redhat.thermostat.client.osgi.service.ApplicationCache;
-import com.redhat.thermostat.client.osgi.service.ApplicationService;
-
-public class ApplicationServiceProvider implements ApplicationService {
-
-    private ApplicationCache cache = new ApplicationCache();
-
-    // NOTE: When merging with ApplicationContext, this could be provided by the same
-    // thread pool that does the timer scheduling. Not sure we want this though,
-    // as scheduled thread pools are always limited in number of threads (could lead to deadlocks
-    // when used carelessly).
-    private ExecutorService executor = Executors.newCachedThreadPool();
-
-    @Override
-    public ApplicationCache getApplicationCache() {
-        return cache;
-    }
-
-    @Override
-    public ExecutorService getApplicationExecutor() {
-        return executor;
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/osgi/ContextActionServiceProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +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.internal.osgi;
-
-import com.redhat.thermostat.client.osgi.service.ContextAction;
-
-public class ContextActionServiceProvider implements ContextAction {
-  
-    @Override
-    public String getName() {
-        return "system context";
-    }
-
-    @Override
-    public String getDescription() {
-        return "system context";
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/osgi/ThermostatActivator.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +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.internal.osgi;
-
-import java.util.Arrays;
-
-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.client.core.views.AgentInformationViewProvider;
-import com.redhat.thermostat.client.core.views.ClientConfigViewProvider;
-import com.redhat.thermostat.client.core.views.HostCpuViewProvider;
-import com.redhat.thermostat.client.core.views.HostInformationViewProvider;
-import com.redhat.thermostat.client.core.views.HostMemoryViewProvider;
-import com.redhat.thermostat.client.core.views.HostOverviewViewProvider;
-import com.redhat.thermostat.client.core.views.SummaryViewProvider;
-import com.redhat.thermostat.client.core.views.VmCpuViewProvider;
-import com.redhat.thermostat.client.core.views.VmGcViewProvider;
-import com.redhat.thermostat.client.core.views.VmInformationViewProvider;
-import com.redhat.thermostat.client.core.views.VmOverviewViewProvider;
-import com.redhat.thermostat.client.internal.GUIClientCommand;
-import com.redhat.thermostat.client.internal.HostIconDecorator;
-import com.redhat.thermostat.client.internal.Main;
-import com.redhat.thermostat.client.internal.UiFacadeFactoryImpl;
-import com.redhat.thermostat.client.osgi.service.HostDecorator;
-import com.redhat.thermostat.client.swing.SwingAgentInformationViewProvider;
-import com.redhat.thermostat.client.swing.SwingClientConfigurationViewProvider;
-import com.redhat.thermostat.client.swing.SwingHostCpuViewProvider;
-import com.redhat.thermostat.client.swing.SwingHostInformationViewProvider;
-import com.redhat.thermostat.client.swing.SwingHostMemoryViewProvider;
-import com.redhat.thermostat.client.swing.SwingHostOverviewViewProvider;
-import com.redhat.thermostat.client.swing.SwingSummaryViewProvider;
-import com.redhat.thermostat.client.swing.SwingVmCpuViewProvider;
-import com.redhat.thermostat.client.swing.SwingVmGcViewProvider;
-import com.redhat.thermostat.client.swing.SwingVmInformationViewProvider;
-import com.redhat.thermostat.client.swing.SwingVmOverviewViewProvider;
-import com.redhat.thermostat.client.ui.UiFacadeFactory;
-import com.redhat.thermostat.common.cli.CommandRegistry;
-import com.redhat.thermostat.common.cli.CommandRegistryImpl;
-import com.redhat.thermostat.utils.keyring.Keyring;
-
-public class ThermostatActivator implements BundleActivator {
-
-    private VmInformationServiceTracker vmInfoServiceTracker;
-    private VMContextActionServiceTracker contextActionTracker;
-
-    private CommandRegistry cmdReg;
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Override
-    public void start(final BundleContext context) throws Exception {
-        
-        HostDecorator hostDecorator = new HostIconDecorator();
-        context.registerService(HostDecorator.class.getName(), hostDecorator, null);
-        
-        // Host views
-        HostInformationViewProvider infoProvider = new SwingHostInformationViewProvider();
-        context.registerService(HostInformationViewProvider.class.getName(), infoProvider, null);
-        HostCpuViewProvider cpuProvider = new SwingHostCpuViewProvider();
-        context.registerService(HostCpuViewProvider.class.getName(), cpuProvider, null);
-        HostOverviewViewProvider provider = new SwingHostOverviewViewProvider();
-        context.registerService(HostOverviewViewProvider.class.getName(), provider, null);
-        HostMemoryViewProvider memoryProvider = new SwingHostMemoryViewProvider();
-        context.registerService(HostMemoryViewProvider.class.getName(), memoryProvider, null);
-        
-        // Vm views
-        VmInformationViewProvider vmInfoProvider = new SwingVmInformationViewProvider();
-        context.registerService(VmInformationViewProvider.class.getName(), vmInfoProvider, null);
-        VmOverviewViewProvider vmOverviewProvider = new SwingVmOverviewViewProvider();
-        context.registerService(VmOverviewViewProvider.class.getName(), vmOverviewProvider, null);
-        VmGcViewProvider vmGcProvider = new SwingVmGcViewProvider();
-        context.registerService(VmGcViewProvider.class.getName(), vmGcProvider, null);
-        VmCpuViewProvider vmCpuProvider = new SwingVmCpuViewProvider();
-        context.registerService(VmCpuViewProvider.class.getName(), vmCpuProvider, null);
-        
-        // Summary view
-        SummaryViewProvider summaryViewProvider = new SwingSummaryViewProvider();
-        context.registerService(SummaryViewProvider.class.getName(), summaryViewProvider, null);
-
-        // AgentInformation and ClientConfiguraiton view
-        AgentInformationViewProvider agentViewProvider = new SwingAgentInformationViewProvider();
-        context.registerService(AgentInformationViewProvider.class.getName(), agentViewProvider, null);
-        ClientConfigViewProvider clientConfigViewProvider = new SwingClientConfigurationViewProvider();
-        context.registerService(ClientConfigViewProvider.class, clientConfigViewProvider, null);
-        
-        ServiceTracker tracker = new ServiceTracker(context, Keyring.class.getName(), null) {
-            @Override
-            public Object addingService(ServiceReference reference) {
-              
-                Keyring keyring = (Keyring) context.getService(reference);
-                
-                UiFacadeFactory uiFacadeFactory = new UiFacadeFactoryImpl(context);
-
-                vmInfoServiceTracker = new VmInformationServiceTracker(context, uiFacadeFactory);
-                vmInfoServiceTracker.open();
-                contextActionTracker = new VMContextActionServiceTracker(context, uiFacadeFactory);
-                contextActionTracker.open();
-
-                cmdReg = new CommandRegistryImpl(context);
-                Main main = new Main(keyring, uiFacadeFactory, new String[0]);
-                
-                GUIClientCommand cmd = new GUIClientCommand(main);
-                cmd.setBundleContext(context);
-                cmdReg.registerCommands(Arrays.asList(cmd));
-                
-                return super.addingService(reference);
-            }
-        };
-        tracker.open();
-    }
-
-    @Override
-    public void stop(BundleContext context) throws Exception {
-        vmInfoServiceTracker.close(); //context.removeServiceListener(vmInfoServiceTracker);
-        contextActionTracker.close();
-        cmdReg.unregisterCommands();
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/osgi/VMContextActionServiceTracker.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.internal.osgi;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
-
-import com.redhat.thermostat.client.osgi.service.VMContextAction;
-import com.redhat.thermostat.client.ui.UiFacadeFactory;
-
-@SuppressWarnings("rawtypes")
-class VMContextActionServiceTracker extends ServiceTracker {
-
-    private UiFacadeFactory uiFacadeFactory;
-
-    private BundleContext context;
-
-    @SuppressWarnings("unchecked")
-    VMContextActionServiceTracker(BundleContext context, UiFacadeFactory uiFacadeFactory) {
-        super(context, VMContextAction.class.getName(), null);
-        this.context = context;
-        this.uiFacadeFactory = uiFacadeFactory;
-    }
-
-    @Override
-    public Object addingService(ServiceReference reference) {
-        @SuppressWarnings("unchecked")
-        VMContextAction service = (VMContextAction) context.getService(reference);
-        uiFacadeFactory.addVMContextAction(service);
-        return service;
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/osgi/VmInformationServiceTracker.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.internal.osgi;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceEvent;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
-
-import com.redhat.thermostat.client.core.VmInformationService;
-import com.redhat.thermostat.client.ui.UiFacadeFactory;
-
-class VmInformationServiceTracker extends ServiceTracker {
-
-    private UiFacadeFactory uiFacadeFactory;
-
-    private BundleContext context;
-
-    VmInformationServiceTracker(BundleContext context, UiFacadeFactory uiFacadeFactory) {
-        super(context, VmInformationService.class.getName(), null);
-        this.context = context;
-        this.uiFacadeFactory = uiFacadeFactory;
-    }
-
-    @Override
-    public Object addingService(ServiceReference reference) {
-        VmInformationService service = (VmInformationService) super.addingService(reference);
-        uiFacadeFactory.addVmInformationService(service);
-        return service;
-    }
-
-    @Override
-    public void removedService(ServiceReference reference, Object service) {
-        uiFacadeFactory.removeVmInformationService((VmInformationService)service);
-        super.removedService(reference, service);
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/ui/swing/AboutDialog.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,288 +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.internal.ui.swing;
-
-import java.awt.Cursor;
-import java.awt.Desktop;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.net.URI;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.swing.GroupLayout;
-import javax.swing.GroupLayout.Alignment;
-import javax.swing.Icon;
-import javax.swing.JButton;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.LayoutStyle.ComponentPlacement;
-import javax.swing.SwingConstants;
-import javax.swing.SwingWorker;
-
-import javax.swing.border.TitledBorder;
-
-import com.redhat.thermostat.client.locale.LocaleResources;
-import com.redhat.thermostat.client.ui.IconResource;
-import com.redhat.thermostat.client.ui.UIResources;
-import com.redhat.thermostat.common.ApplicationInfo;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-
-public class AboutDialog extends JDialog {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-    private static final long serialVersionUID = -7611616871710076514L;
-
-    private static final Logger logger = LoggingUtils.getLogger(AboutDialog.class);
-
-    private String name;
-    private String description;
-    private String version;
-    private Icon icon;
-    private String copyright;
-    private String license;
-    private String website;
-    private String email;
-    
-    /**
-     * Create the dialog.
-     * @param applicationInfo 
-     */
-    public AboutDialog(ApplicationInfo appInfo) {
-        setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
-        setResizable(false);
-        
-        name = appInfo.getName();
-        description = appInfo.getDescription();
-        version = appInfo.getVersion().getVersionNumber();
-        icon = IconResource.QUESTION.getIcon();
-        copyright = appInfo.getCopyright();
-        license = appInfo.getLicenseSummary();
-        website = appInfo.getWebsite();
-        email = appInfo.getEmail();
-        
-        initComponents();
-    }
-    
-    private void initComponents() {
-        setBounds(100, 100, 450, 338);
-        
-        UIResources res = UIResources.getInstance();
-        
-        JPanel panel = new JPanel();
-        panel.setBorder(new TitledBorder(""));
-        
-        JButton closeButton = new JButton(translator.localize(LocaleResources.BUTTON_CLOSE));
-        closeButton.addActionListener(new ActionListener() {
-            public void actionPerformed(ActionEvent e) {
-                AboutDialog.this.setVisible(false);
-                AboutDialog.this.dispose();  
-            }
-        });
-        
-        GroupLayout groupLayout = new GroupLayout(getContentPane());
-        groupLayout.setHorizontalGroup(
-            groupLayout.createParallelGroup(Alignment.TRAILING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addContainerGap()
-                    .addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
-                        .addComponent(closeButton, GroupLayout.PREFERRED_SIZE, 92, GroupLayout.PREFERRED_SIZE)
-                        .addComponent(panel, GroupLayout.DEFAULT_SIZE, 424, Short.MAX_VALUE))
-                    .addContainerGap())
-        );
-        groupLayout.setVerticalGroup(
-            groupLayout.createParallelGroup(Alignment.LEADING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addContainerGap()
-                    .addComponent(panel, GroupLayout.DEFAULT_SIZE, 245, Short.MAX_VALUE)
-                    .addGap(18)
-                    .addComponent(closeButton)
-                    .addGap(9))
-        );
-        
-        JLabel iconLabel = new JLabel("");
-        iconLabel.setHorizontalAlignment(SwingConstants.CENTER);
-        
-        iconLabel.setIcon(icon);
-        
-        JLabel versionLabel = new JLabel(version);
-        versionLabel.setFont(res.footerFont());
-        versionLabel.setHorizontalAlignment(SwingConstants.CENTER);
-        
-        JLabel nameLabel = new JLabel(name);
-        nameLabel.setFont(res.headerFont());
-        nameLabel.setHorizontalAlignment(SwingConstants.CENTER);
-        
-        JLabel descriptionLabel = new JLabel(description);
-        descriptionLabel.setHorizontalAlignment(SwingConstants.CENTER);
-        descriptionLabel.setFont(res.standardFont());
-        
-        JLabel homePageLabel = new JLabel(website);
-        homePageLabel.setForeground(res.hyperlinkColor());
-        homePageLabel.setHorizontalAlignment(SwingConstants.CENTER);
-        homePageLabel.setFont(res.footerFont());        
-        homePageLabel.addMouseListener(new Browse(homePageLabel));
-
-        JLabel copyrightLabel = new JLabel(copyright);
-        copyrightLabel.setHorizontalAlignment(SwingConstants.CENTER);
-        copyrightLabel.setFont(res.footerFont());
-        
-        JLabel licenseString = new JLabel(license);
-        licenseString.setHorizontalAlignment(SwingConstants.CENTER);
-        licenseString.setFont(res.footerFont());
-        
-        JLabel emailLabel = new JLabel(email);
-        emailLabel.setHorizontalAlignment(SwingConstants.CENTER);
-        emailLabel.setForeground(res.hyperlinkColor());
-        emailLabel.setFont(res.footerFont());
-        emailLabel.addMouseListener(new Mailer(emailLabel));
-        
-        GroupLayout gl_panel = new GroupLayout(panel);
-        gl_panel.setHorizontalGroup(
-            gl_panel.createParallelGroup(Alignment.TRAILING)
-                .addGroup(gl_panel.createSequentialGroup()
-                    .addContainerGap()
-                    .addGroup(gl_panel.createParallelGroup(Alignment.LEADING)
-                        .addComponent(iconLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 398, Short.MAX_VALUE)
-                        .addComponent(nameLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 398, Short.MAX_VALUE)
-                        .addComponent(versionLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 398, Short.MAX_VALUE)
-                        .addComponent(descriptionLabel, GroupLayout.DEFAULT_SIZE, 398, Short.MAX_VALUE)
-                        .addComponent(copyrightLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 398, Short.MAX_VALUE)
-                        .addComponent(licenseString, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 398, Short.MAX_VALUE)
-                        .addComponent(emailLabel, GroupLayout.DEFAULT_SIZE, 398, Short.MAX_VALUE)
-                        .addComponent(homePageLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 398, Short.MAX_VALUE))
-                    .addContainerGap())
-        );
-        gl_panel.setVerticalGroup(
-            gl_panel.createParallelGroup(Alignment.LEADING)
-                .addGroup(gl_panel.createSequentialGroup()
-                    .addContainerGap()
-                    .addComponent(iconLabel)
-                    .addGap(4)
-                    .addComponent(nameLabel, GroupLayout.DEFAULT_SIZE, 24, Short.MAX_VALUE)
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addComponent(versionLabel, GroupLayout.DEFAULT_SIZE, 13, Short.MAX_VALUE)
-                    .addPreferredGap(ComponentPlacement.UNRELATED)
-                    .addComponent(descriptionLabel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                    .addGap(12)
-                    .addComponent(homePageLabel, GroupLayout.DEFAULT_SIZE, 19, Short.MAX_VALUE)
-                    .addGap(3)
-                    .addComponent(emailLabel, GroupLayout.DEFAULT_SIZE, 19, Short.MAX_VALUE)
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addComponent(copyrightLabel, GroupLayout.DEFAULT_SIZE, 13, Short.MAX_VALUE)
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addComponent(licenseString, GroupLayout.DEFAULT_SIZE, 13, Short.MAX_VALUE)
-                    .addContainerGap())
-        );
-        panel.setLayout(gl_panel);
-        getContentPane().setLayout(groupLayout);
-    }
-    
-    private abstract class HyperLinkAction extends MouseAdapter {
-        
-        private JLabel hyperLinkLabel;
-        public HyperLinkAction(JLabel hyperLinkLabel) {
-            this.hyperLinkLabel = hyperLinkLabel;
-        }
-        
-        @Override
-        public void mouseEntered(MouseEvent e) {
-            hyperLinkLabel.setForeground(UIResources.getInstance().hyperlinkActiveColor());
-            Cursor cursor = new Cursor(Cursor.HAND_CURSOR);
-            setCursor(cursor);
-        }
-        @Override
-        public void mouseExited(MouseEvent e) {
-            hyperLinkLabel.setForeground(UIResources.getInstance().hyperlinkColor());
-            Cursor cursor = new Cursor(Cursor.DEFAULT_CURSOR);
-            setCursor(cursor);
-        }
-        
-        @Override
-        public void mouseClicked(MouseEvent e) {
-            if (Desktop.isDesktopSupported()) {
-                new SwingWorker<Void, Void>() {
-                    @Override
-                    protected Void doInBackground() throws Exception {
-                        doAction();
-                        return null;
-                    }
-                    @Override
-                    protected void done() {
-                        hyperLinkLabel.setForeground(UIResources.getInstance().hyperlinkColor());
-                    }
-                }.execute();
-            }
-        }
-        
-        protected abstract void doAction();
-    }
-    
-    private class Mailer extends HyperLinkAction {
-        public Mailer(JLabel hyperLinkLabel) {
-            super(hyperLinkLabel);
-        }
-
-        @Override
-        protected void doAction() {
-            try {
-                Desktop.getDesktop().mail(new URI("mailto:" + email));
-            } catch (Exception ex) {
-                logger.log(Level.WARNING, "Cannot send mail to Thermosat mail", ex);
-            }
-        }
-    }
-    
-    private class Browse extends HyperLinkAction {
-        public Browse(JLabel hyperLinkLabel) {
-            super(hyperLinkLabel);
-        }
-        
-        @Override
-        protected void doAction() {
-            try {
-                Desktop.getDesktop().browse(new URI(website));
-            } catch (Exception ex) {
-                logger.log(Level.WARNING, "Cannot open Thermostat website URL", ex);
-            }
-        }
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/internal/ui/swing/WrapLayout.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,229 +0,0 @@
-/*
- * Copyright 2008 Rob Camick, 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.
- */
-
-/*
- * Taken from http://tips4java.wordpress.com/2008/11/06/wrap-layout/
- *
- * The about page (http://tips4java.wordpress.com/about/) says this:
- * "You are free to use and/or modify any or all code posted on the Java Tips
- * Weblog without restriction. A credit in the code comments would be nice,
- * but not in any way mandatory."
- */
-
-package com.redhat.thermostat.client.internal.ui.swing;
-
-import java.awt.*;
-import javax.swing.JScrollPane;
-import javax.swing.SwingUtilities;
-
-/**
- *  FlowLayout subclass that fully supports wrapping of components.
- */
-public class WrapLayout extends FlowLayout {
-
-    private static final long serialVersionUID = -9169664895883997422L;
-
-    /**
-	* Constructs a new <code>WrapLayout</code> with a left
-	* alignment and a default 5-unit horizontal and vertical gap.
-	*/
-	public WrapLayout()
-	{
-		super();
-	}
-
-	/**
-	* Constructs a new <code>FlowLayout</code> with the specified
-	* alignment and a default 5-unit horizontal and vertical gap.
-	* The value of the alignment argument must be one of
-	* <code>WrapLayout</code>, <code>WrapLayout</code>,
-	* or <code>WrapLayout</code>.
-	* @param align the alignment value
-	*/
-	public WrapLayout(int align)
-	{
-		super(align);
-	}
-
-	/**
-	* Creates a new flow layout manager with the indicated alignment
-	* and the indicated horizontal and vertical gaps.
-	* <p>
-	* The value of the alignment argument must be one of
-	* <code>WrapLayout</code>, <code>WrapLayout</code>,
-	* or <code>WrapLayout</code>.
-	* @param align the alignment value
-	* @param hgap the horizontal gap between components
-	* @param vgap the vertical gap between components
-	*/
-	public WrapLayout(int align, int hgap, int vgap)
-	{
-		super(align, hgap, vgap);
-	}
-
-	/**
-	* Returns the preferred dimensions for this layout given the
-	* <i>visible</i> components in the specified target container.
-	* @param target the component which needs to be laid out
-	* @return the preferred dimensions to lay out the
-	* subcomponents of the specified container
-	*/
-	@Override
-	public Dimension preferredLayoutSize(Container target)
-	{
-		return layoutSize(target, true);
-	}
-
-	/**
-	* Returns the minimum dimensions needed to layout the <i>visible</i>
-	* components contained in the specified target container.
-	* @param target the component which needs to be laid out
-	* @return the minimum dimensions to lay out the
-	* subcomponents of the specified container
-	*/
-	@Override
-	public Dimension minimumLayoutSize(Container target)
-	{
-		Dimension minimum = layoutSize(target, false);
-		minimum.width -= (getHgap() + 1);
-		return minimum;
-	}
-
-	/**
-	* Returns the minimum or preferred dimension needed to layout the target
-	* container.
-	*
-	* @param target target to get layout size for
-	* @param preferred should preferred size be calculated
-	* @return the dimension to layout the target container
-	*/
-	private Dimension layoutSize(Container target, boolean preferred)
-	{
-	synchronized (target.getTreeLock())
-	{
-		//  Each row must fit with the width allocated to the containter.
-		//  When the container width = 0, the preferred width of the container
-		//  has not yet been calculated so lets ask for the maximum.
-
-		int targetWidth = target.getSize().width;
-
-		if (targetWidth == 0)
-			targetWidth = Integer.MAX_VALUE;
-
-		int hgap = getHgap();
-		int vgap = getVgap();
-		Insets insets = target.getInsets();
-		int horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2);
-		int maxWidth = targetWidth - horizontalInsetsAndGap;
-
-		//  Fit components into the allowed width
-
-		Dimension dim = new Dimension(0, 0);
-		int rowWidth = 0;
-		int rowHeight = 0;
-
-		int nmembers = target.getComponentCount();
-
-		for (int i = 0; i < nmembers; i++)
-		{
-			Component m = target.getComponent(i);
-
-			if (m.isVisible())
-			{
-				Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize();
-
-				//  Can't add the component to current row. Start a new row.
-
-				if (rowWidth + d.width > maxWidth)
-				{
-					addRow(dim, rowWidth, rowHeight);
-					rowWidth = 0;
-					rowHeight = 0;
-				}
-
-				//  Add a horizontal gap for all components after the first
-
-				if (rowWidth != 0)
-				{
-					rowWidth += hgap;
-				}
-
-				rowWidth += d.width;
-				rowHeight = Math.max(rowHeight, d.height);
-			}
-		}
-
-		addRow(dim, rowWidth, rowHeight);
-
-		dim.width += horizontalInsetsAndGap;
-		dim.height += insets.top + insets.bottom + vgap * 2;
-
-		//	When using a scroll pane or the DecoratedLookAndFeel we need to
-		//  make sure the preferred size is less than the size of the
-		//  target containter so shrinking the container size works
-		//  correctly. Removing the horizontal gap is an easy way to do this.
-
-		Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target);
-
-		if (scrollPane != null)
-		{
-			dim.width -= (hgap + 1);
-		}
-
-		return dim;
-	}
-	}
-
-	/*
-	 *  A new row has been completed. Use the dimensions of this row
-	 *  to update the preferred size for the container.
-	 *
-	 *  @param dim update the width and height when appropriate
-	 *  @param rowWidth the width of the row to add
-	 *  @param rowHeight the height of the row to add
-	 */
-	private void addRow(Dimension dim, int rowWidth, int rowHeight)
-	{
-		dim.width = Math.max(dim.width, rowWidth);
-
-		if (dim.height > 0)
-		{
-			dim.height += getVgap();
-		}
-
-		dim.height += rowHeight;
-	}
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/swing/SwingAgentInformationViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +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.swing;
-
-import com.redhat.thermostat.client.core.views.AgentInformationDisplayView;
-import com.redhat.thermostat.client.core.views.AgentInformationViewProvider;
-import com.redhat.thermostat.client.ui.AgentInformationDisplayFrame;
-
-public class SwingAgentInformationViewProvider implements
-        AgentInformationViewProvider {
-
-    @Override
-    public AgentInformationDisplayView createView() {
-        return new AgentInformationDisplayFrame();
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/swing/SwingClientConfigurationViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +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.swing;
-
-import com.redhat.thermostat.client.core.views.ClientConfigViewProvider;
-import com.redhat.thermostat.client.core.views.ClientConfigurationView;
-import com.redhat.thermostat.client.ui.ClientConfigurationSwing;
-
-public class SwingClientConfigurationViewProvider implements
-        ClientConfigViewProvider {
-
-    @Override
-    public ClientConfigurationView createView() {
-        return new ClientConfigurationSwing();
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/swing/SwingHostCpuViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.swing;
-
-import com.redhat.thermostat.client.core.views.HostCpuView;
-import com.redhat.thermostat.client.core.views.HostCpuViewProvider;
-import com.redhat.thermostat.client.ui.HostCpuPanel;
-
-public class SwingHostCpuViewProvider implements HostCpuViewProvider {
-
-    @Override
-    public HostCpuView createView() {
-        return new HostCpuPanel();
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/swing/SwingHostInformationViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.swing;
-
-import com.redhat.thermostat.client.core.views.HostInformationView;
-import com.redhat.thermostat.client.core.views.HostInformationViewProvider;
-import com.redhat.thermostat.client.ui.HostInformationPanel;
-
-public class SwingHostInformationViewProvider implements HostInformationViewProvider {
-
-    @Override
-    public HostInformationView createView() {
-        return new HostInformationPanel();
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/swing/SwingHostMemoryViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.swing;
-
-import com.redhat.thermostat.client.core.views.HostMemoryView;
-import com.redhat.thermostat.client.core.views.HostMemoryViewProvider;
-import com.redhat.thermostat.client.ui.HostMemoryPanel;
-
-public class SwingHostMemoryViewProvider implements HostMemoryViewProvider {
-
-    @Override
-    public HostMemoryView createView() {
-        return new HostMemoryPanel();
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/swing/SwingHostOverviewViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.swing;
-
-import com.redhat.thermostat.client.core.views.HostOverviewView;
-import com.redhat.thermostat.client.core.views.HostOverviewViewProvider;
-import com.redhat.thermostat.client.ui.HostOverviewPanel;
-
-public class SwingHostOverviewViewProvider implements HostOverviewViewProvider {
-
-    @Override
-    public HostOverviewView createView() {
-        return new HostOverviewPanel();
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/swing/SwingSummaryViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.swing;
-
-import com.redhat.thermostat.client.core.views.SummaryView;
-import com.redhat.thermostat.client.core.views.SummaryViewProvider;
-import com.redhat.thermostat.client.ui.SummaryPanel;
-
-public class SwingSummaryViewProvider implements SummaryViewProvider {
-
-    @Override
-    public SummaryView createView() {
-        return new SummaryPanel();
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/swing/SwingVmCpuViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.swing;
-
-import com.redhat.thermostat.client.core.views.VmCpuView;
-import com.redhat.thermostat.client.core.views.VmCpuViewProvider;
-import com.redhat.thermostat.client.ui.VmCpuPanel;
-
-public class SwingVmCpuViewProvider implements VmCpuViewProvider {
-
-    @Override
-    public VmCpuView createView() {
-        return new VmCpuPanel();
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/swing/SwingVmGcViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.swing;
-
-import com.redhat.thermostat.client.core.views.VmGcView;
-import com.redhat.thermostat.client.core.views.VmGcViewProvider;
-import com.redhat.thermostat.client.ui.VmGcPanel;
-
-public class SwingVmGcViewProvider implements VmGcViewProvider {
-
-    @Override
-    public VmGcView createView() {
-        return new VmGcPanel();
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/swing/SwingVmInformationViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.swing;
-
-import com.redhat.thermostat.client.core.views.VmInformationView;
-import com.redhat.thermostat.client.core.views.VmInformationViewProvider;
-import com.redhat.thermostat.client.ui.VmInformationPanel;
-
-public class SwingVmInformationViewProvider implements VmInformationViewProvider {
-
-    @Override
-    public VmInformationView createView() {
-        return new VmInformationPanel();
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/swing/SwingVmOverviewViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.swing;
-
-import com.redhat.thermostat.client.core.views.VmOverviewView;
-import com.redhat.thermostat.client.core.views.VmOverviewViewProvider;
-import com.redhat.thermostat.client.ui.VmOverviewPanel;
-
-public class SwingVmOverviewViewProvider implements VmOverviewViewProvider {
-
-    @Override
-    public VmOverviewView createView() {
-        return new VmOverviewPanel();
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/AgentInformationDisplayFrame.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,462 +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.ui;
-
-import java.awt.BorderLayout;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import javax.swing.DefaultListModel;
-import javax.swing.GroupLayout;
-import javax.swing.GroupLayout.Alignment;
-import javax.swing.JButton;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JSplitPane;
-import javax.swing.JTable;
-import javax.swing.LayoutStyle.ComponentPlacement;
-import javax.swing.ListSelectionModel;
-import javax.swing.SwingUtilities;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.table.DefaultTableModel;
-
-import com.redhat.thermostat.client.core.views.AgentInformationDisplayView;
-import com.redhat.thermostat.client.locale.LocaleResources;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.locale.Translate;
-
-public class AgentInformationDisplayFrame extends AgentInformationDisplayView {
-
-    private static final Translate<LocaleResources> translate = LocaleResources.createLocalizer();
-
-    private static final String[] BACKEND_TABLE_COLUMN_NAMES = new String[] {
-        translate.localize(LocaleResources.AGENT_INFO_BACKEND_NAME_COLUMN),
-        translate.localize(LocaleResources.AGENT_INFO_BACKEND_STATUS_COLUMN),
-    };
-
-    private final CopyOnWriteArrayList<ActionListener<ConfigurationAction>> listeners = new CopyOnWriteArrayList<>();
-
-    private final JFrame frame;
-
-    private final ConfigurationCompleteListener configurationComplete;
-    private final AgentChangedListener agentChanged;
-    private final WindowClosingListener windowListener;
-
-    private final JButton closeButton;
-
-    private final JList<String> agentList;
-    private final DefaultListModel<String> listModel;
-
-    private final ValueField currentAgentName;
-    private final ValueField currentAgentId;
-    private final ValueField currentAgentCommandAddress;
-    private final ValueField currentAgentStartTime;
-    private final ValueField currentAgentStopTime;
-
-    private final JTable backendsTable;
-    private final DefaultTableModel backendsTableModel;
-    private final ValueField backendDescription;
-
-    public AgentInformationDisplayFrame() {
-        assertInEDT();
-
-        configurationComplete = new ConfigurationCompleteListener();
-        agentChanged = new AgentChangedListener();
-        windowListener = new WindowClosingListener();
-
-        frame = new JFrame();
-        frame.setTitle(translate.localize(LocaleResources.AGENT_INFO_WINDOW_TITLE));
-        frame.addWindowListener(windowListener);
-
-        closeButton = new JButton(translate.localize(LocaleResources.BUTTON_CLOSE));
-        closeButton.addActionListener(configurationComplete);
-        closeButton.setName("close");
-
-        JSplitPane splitPane = new JSplitPane();
-        splitPane.setResizeWeight(0.35);
-
-        GroupLayout mainLayout = new GroupLayout(frame.getContentPane());
-        mainLayout.setHorizontalGroup(
-            mainLayout.createParallelGroup(Alignment.TRAILING)
-                .addGroup(mainLayout.createSequentialGroup()
-                    .addContainerGap()
-                    .addGroup(mainLayout.createParallelGroup(Alignment.TRAILING)
-                        .addComponent(splitPane, GroupLayout.DEFAULT_SIZE, 664, Short.MAX_VALUE)
-                        .addComponent(closeButton))
-                    .addContainerGap()));
-
-        mainLayout.setVerticalGroup(
-            mainLayout.createParallelGroup(Alignment.TRAILING)
-                .addGroup(mainLayout.createSequentialGroup()
-                    .addContainerGap()
-                    .addComponent(splitPane, GroupLayout.DEFAULT_SIZE, 472, Short.MAX_VALUE)
-                    .addPreferredGap(ComponentPlacement.UNRELATED)
-                    .addComponent(closeButton)
-                    .addContainerGap()));
-
-        JPanel agentListPanel = new JPanel();
-        splitPane.setLeftComponent(agentListPanel);
-
-        JLabel agentLabel = new JLabel(translate.localize(LocaleResources.AGENT_INFO_AGENTS_LIST));
-
-        JScrollPane scrollPane = new JScrollPane();
-
-        listModel = new DefaultListModel<String>();
-        agentList = new JList<String>(listModel);
-        agentList.setName("agentList");
-        agentList.addListSelectionListener(agentChanged);
-        agentListPanel.setLayout(new BorderLayout());
-
-        scrollPane.setViewportView(agentList);
-        agentListPanel.add(scrollPane);
-        agentListPanel.add(agentLabel, BorderLayout.NORTH);
-
-        JPanel agentConfigurationPanel = new JPanel();
-        splitPane.setRightComponent(agentConfigurationPanel);
-
-        SectionHeader agentSectionTitle = new SectionHeader(translate.localize(LocaleResources.AGENT_INFO_AGENT_SECTION_TITLE));
-
-        LabelField agentNameLabel = new LabelField(translate.localize(LocaleResources.AGENT_INFO_AGENT_NAME_LABEL));
-        LabelField agentIdLabel = new LabelField(translate.localize(LocaleResources.AGENT_INFO_AGENT_ID_LABEL));
-        LabelField agentConfigurationAddressLabel = new LabelField(translate.localize(LocaleResources.AGENT_INFO_AGENT_COMMAND_ADDRESS_LABEL));
-        LabelField agentStartTimeLabel = new LabelField(translate.localize(LocaleResources.AGENT_INFO_AGENT_START_TIME_LABEL));
-        LabelField agentStopTimeLabel = new LabelField(translate.localize(LocaleResources.AGENT_INFO_AGENT_STOP_TIME_LABEL));
-
-        String notAvailable = translate.localize(LocaleResources.INFORMATION_NOT_AVAILABLE);
-
-        currentAgentName = new ValueField(notAvailable);
-        currentAgentName.setName("agentName");
-        currentAgentId = new ValueField(notAvailable);
-        currentAgentId.setName("agentId");
-        currentAgentCommandAddress = new ValueField(notAvailable);
-        currentAgentCommandAddress.setName("commandAddress");
-        currentAgentStartTime = new ValueField(notAvailable);
-        currentAgentStartTime.setName("startTime");
-        currentAgentStopTime = new ValueField(notAvailable);
-        currentAgentStopTime.setName("stopTime");
-
-        SectionHeader backendSectionTitle = new SectionHeader(translate.localize(LocaleResources.AGENT_INFO_BACKENDS_SECTION_TITLE));
-
-        backendsTableModel = new DefaultTableModel();
-        backendsTableModel.setColumnIdentifiers(BACKEND_TABLE_COLUMN_NAMES);
-
-        backendsTable = new JTable(backendsTableModel);
-        backendsTable.setName("backends");
-        backendsTable.setCellSelectionEnabled(false);
-        backendsTable.setColumnSelectionAllowed(false);
-        backendsTable.setRowSelectionAllowed(true);
-        backendsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-        backendsTable.getSelectionModel().addListSelectionListener(new BackendSelectionListener());
-
-        JScrollPane backendsTableScollPane = new JScrollPane(backendsTable);
-
-        JLabel backendDescriptionLabel = new JLabel(translate.localize(LocaleResources.AGENT_INFO_BACKEND_DESCRIPTION_LABEL));
-        backendDescription = new ValueField(notAvailable);
-        backendDescription.setName("backendDescription");
-
-        GroupLayout agentConfigurationPanelLayout = new GroupLayout(agentConfigurationPanel);
-        agentConfigurationPanelLayout.setHorizontalGroup(
-            agentConfigurationPanelLayout.createParallelGroup()
-                .addComponent(agentSectionTitle, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                .addGroup(agentConfigurationPanelLayout.createSequentialGroup()
-                    .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.LEADING, true)
-                        .addComponent(agentNameLabel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                        .addComponent(agentIdLabel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                        .addComponent(agentConfigurationAddressLabel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                        .addComponent(agentStartTimeLabel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                        .addComponent(agentStopTimeLabel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
-                    .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.LEADING, true)
-                        .addComponent(currentAgentName, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
-                        .addComponent(currentAgentId, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
-                        .addComponent(currentAgentCommandAddress, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
-                        .addComponent(currentAgentStartTime, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
-                        .addComponent(currentAgentStopTime, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)))
-                .addComponent(backendSectionTitle, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
-                .addComponent(backendsTableScollPane, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
-                .addComponent(backendDescriptionLabel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                .addComponent(backendDescription, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE));
-
-        agentConfigurationPanelLayout.setVerticalGroup(
-            agentConfigurationPanelLayout.createSequentialGroup()
-                .addComponent(agentSectionTitle)
-                .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.BASELINE, false)
-                    .addComponent(agentNameLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                    .addComponent(currentAgentName, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
-                .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.BASELINE, false)
-                    .addComponent(agentIdLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                    .addComponent(currentAgentId, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
-                .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.BASELINE, false)
-                    .addComponent(agentConfigurationAddressLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                    .addComponent(currentAgentCommandAddress, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
-                .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.BASELINE, false)
-                    .addComponent(agentStartTimeLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                    .addComponent(currentAgentStartTime, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
-                .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.BASELINE, false)
-                    .addComponent(agentStopTimeLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                    .addComponent(currentAgentStopTime, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
-                .addComponent(backendSectionTitle)
-                .addComponent(backendsTableScollPane)
-                .addComponent(backendDescriptionLabel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE)
-                .addComponent(backendDescription, 30, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE));
-
-        agentConfigurationPanelLayout.setAutoCreateGaps(true);
-        agentConfigurationPanelLayout.setAutoCreateContainerGaps(true);
-        agentConfigurationPanel.setLayout(agentConfigurationPanelLayout);
-
-        frame.getContentPane().setLayout(mainLayout);
-
-    }
-
-    @Override
-    public void addConfigurationListener(ActionListener<ConfigurationAction> listener) {
-        listeners.add(listener);
-    }
-
-    @Override
-    public void removeConfigurationListener(ActionListener<ConfigurationAction> listener) {
-        listeners.remove(listener);
-    }
-
-    @Override
-    public void addAgent(final String agentName) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                listModel.addElement(agentName);
-                if (agentList.getSelectedIndex() == -1) {
-                    agentList.setSelectedIndex(0);
-                }
-            }
-        });
-    }
-
-    @Override
-    public String getSelectedAgent() {
-        assertInEDT();
-        return agentList.getSelectedValue();
-    }
-
-    @Override
-    public void clearAllAgents() {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                listModel.clear();
-            }
-        });
-    }
-
-    @Override
-    public void setSelectedAgentName(final String agentName) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                currentAgentName.setText(agentName);
-            }
-        });
-    }
-
-    @Override
-    public void setSelectedAgentId(final String agentId) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                currentAgentId.setText(agentId);
-            }
-        });
-    }
-
-    @Override
-    public void setSelectedAgentCommandAddress(final String address) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                currentAgentCommandAddress.setText(address);
-            }
-        });
-    }
-
-    @Override
-    public void setSelectedAgentStartTime(final String startTime) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                currentAgentStartTime.setText(startTime);
-            }
-        });
-    }
-
-    @Override
-    public void setSelectedAgentStopTime(final String stopTime) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                currentAgentStopTime.setText(stopTime);
-            }
-        });
-    }
-
-    @Override
-    public void setSelectedAgentBackendStatus(final Map<String, String> backendStatus) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                int i = 0;
-                for (Entry<String, String> entry : backendStatus.entrySet()) {
-                    String backendName = entry.getKey();
-                    String status = entry.getValue();
-                    int rowCount = backendsTableModel.getRowCount();
-                    if (i >= rowCount) {
-                        Object[] rowData = new String[] { backendName, status };
-                        backendsTableModel.insertRow(i, rowData);
-                    } else {
-                        backendsTableModel.setValueAt(backendName, i, 0);
-                        backendsTableModel.setValueAt(status, i, 1);
-                    }
-                    i++;
-                }
-
-                if (backendsTable.getRowCount() > 0 && backendsTable.getSelectedRow() == -1) {
-                    backendsTable.setRowSelectionInterval(0, 0);
-                }
-            }
-        });
-    }
-
-    @Override
-    public void setSelectedAgentBackendDescription(final String description) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                backendDescription.setText(description);
-            }
-        });
-    }
-
-    @Override
-    public void showDialog() {
-        assertInEDT();
-
-        frame.pack();
-        frame.setVisible(true);
-
-        agentList.setSelectedIndex(0);
-    }
-
-    @Override
-    public void hideDialog() {
-        assertInEDT();
-
-        frame.setVisible(false);
-        frame.dispose();
-    }
-
-    /** This is for tests only */
-    JFrame getFrame() {
-        return frame;
-    }
-
-    private void fireAction(ActionEvent<ConfigurationAction> actionEvent) {
-        for (ActionListener<ConfigurationAction> l : listeners) {
-            l.actionPerformed(actionEvent);
-        }
-    }
-
-    private static void assertInEDT() {
-        if (!SwingUtilities.isEventDispatchThread()) {
-            throw new IllegalStateException("must be called from within the swing EDT");
-        }
-    }
-
-    private class ConfigurationCompleteListener implements java.awt.event.ActionListener {
-        @Override
-        public void actionPerformed(java.awt.event.ActionEvent e) {
-            Object source = e.getSource();
-            if (source == closeButton) {
-                fireAction(new ActionEvent<>(AgentInformationDisplayFrame.this, ConfigurationAction.CLOSE));
-            }
-        }
-    }
-
-    private class WindowClosingListener extends WindowAdapter {
-        @Override
-        public void windowClosing(WindowEvent e) {
-            fireAction(new ActionEvent<>(AgentInformationDisplayFrame.this, ConfigurationAction.CLOSE));
-        }
-    }
-
-    private class AgentChangedListener implements ListSelectionListener {
-        @Override
-        public void valueChanged(ListSelectionEvent e) {
-            if (e.getSource() == agentList) {
-                if (e.getValueIsAdjusting()) {
-                    return;
-                }
-                fireAction(new ActionEvent<>(AgentInformationDisplayFrame.this, ConfigurationAction.SWITCH_AGENT));
-            } else {
-                throw new IllegalStateException("unknown trigger");
-            }
-        }
-    }
-
-    private class BackendSelectionListener implements ListSelectionListener {
-
-        @Override
-        public void valueChanged(ListSelectionEvent e) {
-            if (e.getValueIsAdjusting()) {
-                return;
-            }
-
-            int rowIndex = e.getFirstIndex();
-            String backendName = (String) backendsTableModel.getValueAt(rowIndex, 0);
-            ActionEvent<ConfigurationAction> event = new ActionEvent<>(AgentInformationDisplayFrame.this,
-                    ConfigurationAction.SHOW_BACKEND_DESCRIPTION);
-            event.setPayload(backendName);
-            fireAction(event);
-        }
-
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/BytesTickUnit.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.ui;
+
+import org.jfree.chart.axis.NumberTickUnit;
+
+import com.redhat.thermostat.common.utils.DisplayableValues;
+
+@SuppressWarnings("serial")
+public class BytesTickUnit extends NumberTickUnit {
+
+    public BytesTickUnit(double size) {
+        super(size);
+    }
+
+    @Override
+    public String valueToString(double value) {
+        String[] displayable = DisplayableValues.bytes((long) value);
+        return displayable[0] + " " + displayable[1];
+    }
+}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/ChartColors.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/ChartColors.java	Fri Oct 26 15:32:56 2012 +0200
@@ -38,7 +38,6 @@
 
 import java.awt.Color;
 
-import com.redhat.thermostat.swing.Palette;
 
 public class ChartColors {
     private static final Palette[] SERIES_COLORS = {
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/ClientConfigurationPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,138 +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.ui;
-
-import javax.swing.GroupLayout;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JPasswordField;
-import javax.swing.JTextField;
-import javax.swing.GroupLayout.Alignment;
-import javax.swing.LayoutStyle.ComponentPlacement;
-
-import com.redhat.thermostat.client.locale.LocaleResources;
-import com.redhat.thermostat.common.locale.Translate;
-
-import javax.swing.border.TitledBorder;
-import javax.swing.JCheckBox;
-
-@SuppressWarnings("serial")
-class ClientConfigurationPanel extends JPanel {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    final JTextField storageUrl = new JTextField();
-    final JTextField userName = new JTextField();
-    final JPasswordField password = new JPasswordField();
-    
-    final JCheckBox saveEntitlements;
-    
-    public ClientConfigurationPanel() {
-        setBorder(new TitledBorder(null,
-                  translator.localize(LocaleResources.CLIENT_PREFS_CONNECTION),
-                  TitledBorder.LEFT, TitledBorder.TOP, null, null));
-
-        JLabel storageURLText = new JLabel(translator.localize(LocaleResources.CLIENT_PREFS_STORAGE_URL));
-        storageURLText.setName("");
-        
-        storageUrl.setColumns(10);
-        storageUrl.setName("connectionUrl");
-        
-        JLabel userNameText = new JLabel(translator.localize(LocaleResources.CLIENT_PREFS_STORAGE_USERNAME));
-        userNameText.setName("userNameText");
-        
-        userName.setName("username");
-        userName.setColumns(10);
-        
-        JLabel passowrdText = new JLabel("Password");
-        passowrdText.setName("passwordText");
-        
-        password.setName("password");
-        password.setColumns(10);
-        
-        saveEntitlements = new JCheckBox(translator.localize(LocaleResources.CLIENT_PREFS_STORAGE_SAVE_ENTITLEMENTS));
-        saveEntitlements.setName("saveEntitlements");
-        saveEntitlements.setSelected(false);
-
-        GroupLayout groupLayout = new GroupLayout(this);
-        groupLayout.setHorizontalGroup(
-            groupLayout.createParallelGroup(Alignment.TRAILING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addContainerGap()
-                    .addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
-                        .addComponent(saveEntitlements)
-                        .addGroup(groupLayout.createSequentialGroup()
-                            .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
-                                .addComponent(storageURLText, GroupLayout.PREFERRED_SIZE, 83, GroupLayout.PREFERRED_SIZE)
-                                .addGroup(groupLayout.createParallelGroup(Alignment.LEADING, false)
-                                    .addComponent(passowrdText, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                                    .addComponent(userNameText, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
-                            .addPreferredGap(ComponentPlacement.UNRELATED)
-                            .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
-                                .addComponent(userName, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 326, Short.MAX_VALUE)
-                                .addComponent(storageUrl, GroupLayout.DEFAULT_SIZE, 326, Short.MAX_VALUE)
-                                .addComponent(password, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 326, Short.MAX_VALUE))))
-                    .addGap(24))
-        );
-        groupLayout.setVerticalGroup(
-            groupLayout.createParallelGroup(Alignment.LEADING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addContainerGap()
-                    .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
-                        .addComponent(storageURLText)
-                        .addComponent(storageUrl, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
-                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
-                        .addGroup(groupLayout.createSequentialGroup()
-                            .addGap(8)
-                            .addComponent(userNameText))
-                        .addGroup(groupLayout.createSequentialGroup()
-                            .addPreferredGap(ComponentPlacement.RELATED)
-                            .addComponent(userName, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)))
-                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
-                        .addGroup(groupLayout.createSequentialGroup()
-                            .addGap(8)
-                            .addComponent(passowrdText))
-                        .addGroup(groupLayout.createSequentialGroup()
-                            .addPreferredGap(ComponentPlacement.RELATED)
-                            .addComponent(password, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)))
-                    .addPreferredGap(ComponentPlacement.UNRELATED)
-                    .addComponent(saveEntitlements)
-                    .addContainerGap(15, Short.MAX_VALUE))
-        );
-        setLayout(groupLayout);
-    }
-}
\ No newline at end of file
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/ClientConfigurationSwing.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,263 +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.ui;
-
-import java.awt.Frame;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.lang.reflect.InvocationTargetException;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import javax.swing.JDialog;
-import javax.swing.JOptionPane;
-import javax.swing.SwingUtilities;
-import javax.swing.WindowConstants;
-
-import com.redhat.thermostat.client.core.views.ClientConfigurationView;
-import com.redhat.thermostat.client.locale.LocaleResources;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.swing.EdtHelper;
-
-public class ClientConfigurationSwing implements ClientConfigurationView {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private final WindowClosingListener windowClosingListener;
-
-    private final ClientConfigurationPanel configurationPanel;
-
-    private final CopyOnWriteArrayList<ActionListener<Action>> listeners = new CopyOnWriteArrayList<>();
-
-    private JDialog dialog;
-
-    public ClientConfigurationSwing() {
-        assertInEDT();
-
-        windowClosingListener = new WindowClosingListener();
-        configurationPanel = new ClientConfigurationPanel();
-        
-        final JOptionPane optionPane = new JOptionPane(configurationPanel);
-        optionPane.setOptionType(JOptionPane.OK_CANCEL_OPTION);
-        optionPane.addPropertyChangeListener(new PropertyChangeListener() {
-            @Override
-            public void propertyChange(PropertyChangeEvent evt) {
-                String propertyName = evt.getPropertyName();
-                if ((evt.getSource() == optionPane) &&
-                    (propertyName.equals(JOptionPane.VALUE_PROPERTY))) {
-                    if (dialog.isVisible()) {
-                        if (evt.getNewValue().equals(JOptionPane.OK_OPTION)) {
-                            fireAction(new ActionEvent<>(ClientConfigurationSwing.this, Action.CLOSE_ACCEPT));
-                        } else if (evt.getNewValue().equals(JOptionPane.CANCEL_OPTION)) {
-                            fireAction(new ActionEvent<>(ClientConfigurationSwing.this, Action.CLOSE_CANCEL));
-                        }
-                    }
-                }
-            }
-        });
-
-        dialog = new JDialog((Frame) null, translator.localize(LocaleResources.CLIENT_PREFS_WINDOW_TITLE));
-        dialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
-        dialog.setContentPane(optionPane);
-        dialog.addWindowListener(windowClosingListener);
-    }
-
-    JDialog getDialog() {
-        return dialog;
-    }
-
-    @Override
-    public void showDialog() {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                dialog.pack();
-                dialog.setVisible(true);
-            }
-        });
-    }
-
-    @Override
-    public void hideDialog() {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                dialog.setVisible(false);
-                dialog.dispose();
-                dialog = null;
-            }
-
-        });
-    }
-
-    @Override
-    public String getConnectionUrl() {
-        try {
-            return new EdtHelper().callAndWait(new Callable<String>() {
-                @Override
-                public String call() throws Exception {
-                    return configurationPanel.storageUrl.getText();
-                }
-            });
-        } catch (InvocationTargetException | InterruptedException e) {
-            InternalError error = new InternalError();
-            error.initCause(e);
-            throw error;
-        }
-    }
-
-    @Override
-    public void setConnectionUrl(final String url) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                configurationPanel.storageUrl.setText(url);
-            }
-        });
-    }
-
-    @Override
-    public void addListener(ActionListener<Action> listener) {
-        listeners.add(listener);
-    }
-
-    @Override
-    public void removeListener(ActionListener<Action> listener) {
-        listeners.remove(listener);
-    }
-
-    private void fireAction(ActionEvent<Action> actionEvent) {
-        for (ActionListener<Action> listener: listeners) {
-            listener.actionPerformed(actionEvent);
-        }
-    }
-
-    private void assertInEDT() {
-        if (!SwingUtilities.isEventDispatchThread()) {
-            throw new IllegalStateException("must be invoked in the EDT");
-        }
-    }
-
-    class WindowClosingListener extends WindowAdapter {
-        @Override
-        public void windowClosing(WindowEvent e) {
-            fireAction(new ActionEvent<>(ClientConfigurationSwing.this, Action.CLOSE_CANCEL));
-        }
-    }
-
-    @Override
-    public void setPassword(final String password) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                configurationPanel.password.setText(password);
-            }
-        });
-    }
-    
-    @Override
-    public void setUserName(final String username) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                configurationPanel.userName.setText(username);
-            }
-        });
-    };
-    
-    @Override
-    public String getPassword() {
-        try {
-            return new EdtHelper().callAndWait(new Callable<String>() {
-                @Override
-                public String call() throws Exception {
-                    return configurationPanel.password.getText();
-                }
-            });
-        } catch (InvocationTargetException | InterruptedException e) {
-            InternalError error = new InternalError();
-            error.initCause(e);
-            throw error;
-        }
-    }
-    
-    @Override
-    public String getUserName() {
-        try {
-            return new EdtHelper().callAndWait(new Callable<String>() {
-                @Override
-                public String call() throws Exception {
-                    return configurationPanel.userName.getText();
-                }
-            });
-        } catch (InvocationTargetException | InterruptedException e) {
-            InternalError error = new InternalError();
-            error.initCause(e);
-            throw error;
-        }
-    }
-    
-    @Override
-    public boolean getSaveEntitlements() {
-        try {
-            return new EdtHelper().callAndWait(new Callable<Boolean>() {
-                @Override
-                public Boolean call() throws Exception {
-                    return configurationPanel.saveEntitlements.isSelected();
-                }
-            });
-        } catch (InvocationTargetException | InterruptedException e) {
-            InternalError error = new InternalError();
-            error.initCause(e);
-            throw error;
-        }
-    }
-    
-    @Override
-    public void setSaveEntitlemens(final boolean save) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                configurationPanel.saveEntitlements.setSelected(save);
-            }
-        });
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/Components.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +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.ui;
-
-import javax.swing.BorderFactory;
-import javax.swing.JLabel;
-import javax.swing.SwingConstants;
-import javax.swing.border.Border;
-
-public class Components {
-    public static JLabel header(String text) {
-        JLabel label = new JLabel(HtmlTextBuilder.boldHtml(text));
-        label.setHorizontalAlignment(SwingConstants.LEADING);
-        return label;
-    }
-
-    public static JLabel label(String string) {
-        JLabel label = new JLabel(string);
-        label.setHorizontalAlignment(SwingConstants.TRAILING);
-        return label;
-    }
-
-    public static Border smallBorder() {
-        return BorderFactory.createEmptyBorder(5, 5, 5, 5);
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/DecoratedDefaultMutableTreeNode.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.ui;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.tree.DefaultMutableTreeNode;
-
-import com.redhat.thermostat.client.osgi.service.VmDecorator;
-import com.redhat.thermostat.common.dao.Ref;
-
-class DecoratedDefaultMutableTreeNode  extends DefaultMutableTreeNode {
-    
-    private List<Decorator> decorators;
-    
-    DecoratedDefaultMutableTreeNode(Ref ref) {
-        super(ref);
-        decorators = new ArrayList<>();
-    }
-    
-    public void addDecorator(Decorator decorator) {
-        decorators.add(decorator);
-    }
-    
-    public void setDecorators(List<Decorator> decorators) {
-        this.decorators = decorators;
-    }
-    
-    public List<Decorator> getDecorators() {
-        return decorators;
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/Decorator.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/Decorator.java	Fri Oct 26 15:32:56 2012 +0200
@@ -36,7 +36,6 @@
 
 package com.redhat.thermostat.client.ui;
 
-
 /**
  * A {@link Decorator} allows plugins to install special visual clues on
  * selected components.
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/HostCpuPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,289 +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.ui;
-
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.FlowLayout;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-import javax.swing.GroupLayout;
-import javax.swing.GroupLayout.Alignment;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.LayoutStyle.ComponentPlacement;
-import javax.swing.SwingUtilities;
-import javax.swing.text.JTextComponent;
-
-import org.jfree.chart.ChartFactory;
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.renderer.xy.XYItemRenderer;
-import org.jfree.data.time.FixedMillisecond;
-import org.jfree.data.time.RegularTimePeriod;
-import org.jfree.data.time.TimeSeries;
-import org.jfree.data.time.TimeSeriesCollection;
-
-import com.redhat.thermostat.client.core.views.HostCpuView;
-import com.redhat.thermostat.client.internal.ui.swing.WrapLayout;
-import com.redhat.thermostat.client.locale.LocaleResources;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.model.DiscreteTimeData;
-
-public class HostCpuPanel extends HostCpuView implements SwingComponent {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private JPanel visiblePanel;
-
-    private final JTextComponent cpuModel = new ValueField("${CPU_MODEL}");
-    private final JTextComponent cpuCount = new ValueField("${CPU_COUNT}");
-
-    private final TimeSeriesCollection datasetCollection = new TimeSeriesCollection();
-    private final Map<Integer, TimeSeries> datasets = new HashMap<>();
-    private final Map<String, Color> colors = new HashMap<>();
-    private final Map<String, JLabel> labels = new HashMap<>();
-
-    private JFreeChart chart;
-
-    private JPanel legendPanel;
-
-    public HostCpuPanel() {
-        super();
-        initializePanel();
-
-        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
-            @Override
-            public void componentShown(Component component) {
-                notifier.fireAction(Action.VISIBLE);
-            }
-            @Override
-            public void componentHidden(Component component) {
-                notifier.fireAction(Action.HIDDEN);
-            }
-        });
-    }
-
-    @Override
-    public void addActionListener(ActionListener<Action> listener) {
-       notifier.addActionListener(listener);
-    }
-
-    @Override
-    public void removeActionListener(ActionListener<Action> listener) {
-        notifier.removeActionListener(listener);
-    }
-
-    @Override
-    public void setCpuCount(final String count) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                cpuCount.setText(count);
-            }
-        });
-    }
-
-    @Override
-    public void setCpuModel(final String model) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                cpuModel.setText(model);
-            }
-        });
-    }
-
-    @Override
-    public void addCpuUsageChart(final int cpuIndex, final String humanReadableName) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                TimeSeries series = new TimeSeries(humanReadableName);
-                Color color = ChartColors.getColor(colors.size());
-                colors.put(humanReadableName, color);
-
-                datasets.put(cpuIndex, series);
-                datasetCollection.addSeries(series);
-
-                updateColors();
-
-                JLabel label = createLabelWithLegend(humanReadableName, color);
-                labels.put(humanReadableName, label);
-
-                legendPanel.add(label);
-                legendPanel.revalidate();
-            }
-        });
-    }
-
-    @Override
-    public void addCpuUsageData(final int cpuIndex, List<DiscreteTimeData<Double>> data) {
-        final ArrayList<DiscreteTimeData<Double>> copy = new ArrayList<>(data);
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                TimeSeries dataset = datasets.get(cpuIndex);
-                for (DiscreteTimeData<Double> timeData: copy) {
-                    RegularTimePeriod period = new FixedMillisecond(timeData.getTimeInMillis());
-                    if (dataset.getDataItem(period) == null) {
-                        dataset.add(period, timeData.getData(), false);
-                    }
-                }
-                dataset.fireSeriesChanged();
-            }
-        });
-    }
-
-    @Override
-    public void clearCpuUsageData() {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                for (Iterator<Map.Entry<Integer, TimeSeries>> iter = datasets.entrySet().iterator(); iter.hasNext();) {
-                    Map.Entry<Integer, TimeSeries> entry = iter.next();
-                    datasetCollection.removeSeries(entry.getValue());
-                    entry.getValue().clear();
-
-                    iter.remove();
-
-                }
-                updateColors();
-            }
-        });
-    }
-
-    @Override
-    public Component getUiComponent() {
-        return visiblePanel;
-    }
-
-    private void initializePanel() {
-
-        visiblePanel = new JPanel();
-
-        JLabel summaryLabel = new SectionHeader(translator.localize(LocaleResources.HOST_CPU_SECTION_OVERVIEW));
-
-        JLabel cpuModelLabel = new LabelField(translator.localize(LocaleResources.HOST_INFO_CPU_MODEL));
-
-        JLabel cpuCountLabel = new LabelField(translator.localize(LocaleResources.HOST_INFO_CPU_COUNT));
-
-        chart = ChartFactory.createTimeSeriesChart(
-                null,
-                translator.localize(LocaleResources.HOST_CPU_USAGE_CHART_TIME_LABEL),
-                translator.localize(LocaleResources.HOST_CPU_USAGE_CHART_VALUE_LABEL),
-                datasetCollection,
-                false, false, false);
-
-        chart.getPlot().setBackgroundPaint( new Color(255,255,255,0) );
-        chart.getPlot().setBackgroundImageAlpha(0.0f);
-        chart.getPlot().setOutlinePaint(new Color(0,0,0,0));
-
-        JPanel chartPanel = new RecentTimeSeriesChartPanel(new RecentTimeSeriesChartController(chart));
-        chartPanel.setOpaque(false);
-
-        legendPanel = new JPanel(new WrapLayout(FlowLayout.LEADING));
-        legendPanel.setOpaque(false);
-
-        GroupLayout groupLayout = new GroupLayout(visiblePanel);
-        groupLayout.setHorizontalGroup(
-            groupLayout.createParallelGroup(Alignment.TRAILING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addContainerGap()
-                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
-                        .addComponent(legendPanel, GroupLayout.DEFAULT_SIZE, 427, Short.MAX_VALUE)
-                        .addComponent(chartPanel, GroupLayout.DEFAULT_SIZE, 427, Short.MAX_VALUE)
-                        .addComponent(summaryLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                        .addGroup(groupLayout.createSequentialGroup()
-                            .addGap(12)
-                            .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
-                                .addGroup(groupLayout.createSequentialGroup()
-                                    .addPreferredGap(ComponentPlacement.RELATED)
-                                    .addComponent(cpuCountLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                                    .addGap(18)
-                                    .addComponent(cpuCount, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
-                                .addGroup(groupLayout.createSequentialGroup()
-                                    .addComponent(cpuModelLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                                    .addGap(18)
-                                    .addComponent(cpuModel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))
-                    .addGap(11))
-        );
-        groupLayout.setVerticalGroup(
-            groupLayout.createParallelGroup(Alignment.LEADING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addContainerGap()
-                    .addComponent(summaryLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
-                        .addComponent(cpuModelLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                        .addComponent(cpuModel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
-                    .addGap(10)
-                    .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
-                        .addComponent(cpuCount, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                        .addComponent(cpuCountLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
-                    .addGap(18)
-                    .addComponent(chartPanel, GroupLayout.DEFAULT_SIZE, 263, Short.MAX_VALUE)
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addComponent(legendPanel, GroupLayout.PREFERRED_SIZE, 30, GroupLayout.PREFERRED_SIZE)
-                    .addContainerGap())
-        );
-        visiblePanel.setLayout(groupLayout);
-    }
-
-    /**
-     * Adding or removing series to the series collection may change the order
-     * of existing items. Plus the paint for the index is now out-of-date. So
-     * let's walk through all the series and set the right paint for those.
-     */
-    private void updateColors() {
-        XYItemRenderer itemRenderer = chart.getXYPlot().getRenderer();
-        for (int i = 0; i < datasetCollection.getSeriesCount(); i++) {
-            String tag = (String) datasetCollection.getSeriesKey(i);
-            Color color = colors.get(tag);
-            itemRenderer.setSeriesPaint(i, color);
-        }
-    }
-
-    private JLabel createLabelWithLegend(String text, Color color) {
-        String hexColor = "#" + Integer.toHexString(color.getRGB() & 0x00ffffff);
-        return new JLabel("<html> <font color='" + hexColor + "'>\u2588</font> " + text + "</html>");
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/HostInformationPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +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.ui;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-
-import javax.swing.JPanel;
-import javax.swing.JTabbedPane;
-import javax.swing.SwingUtilities;
-
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.core.views.HostInformationView;
-
-public class HostInformationPanel extends HostInformationView implements SwingComponent {
-
-    private JPanel visiblePanel;
-    private final JTabbedPane tabPane;
-
-    private int viewCount = 0;
-
-    public HostInformationPanel() {
-        super();
-        visiblePanel = new JPanel();
-        visiblePanel.setLayout(new BorderLayout());
-        tabPane = new JTabbedPane();
-        visiblePanel.add(tabPane);
-    }
-
-    @Override
-    public void addChildView(final String title, final BasicView view) {
-        if (view instanceof SwingComponent) {
-            final SwingComponent component = (SwingComponent)view;
-            SwingUtilities.invokeLater(new Runnable() {
-                @Override
-                public void run() {
-                    tabPane.insertTab(title, null, component.getUiComponent(), null, viewCount);
-                    viewCount++;
-                }
-                
-            });
-        }
-    }
-
-    @Override
-    public void removeChildView(final String title) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 0; i < viewCount; i++) {
-                    if (tabPane.getTitleAt(i).equals(title)) {
-                        tabPane.remove(i);
-                        return;
-                    }
-                }
-            }
-        });
-    }
-
-    @Override
-    public Component getUiComponent() {
-        return visiblePanel;
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/HostMemoryPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,347 +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.ui;
-
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.FlowLayout;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import javax.swing.GroupLayout;
-import javax.swing.GroupLayout.Alignment;
-import javax.swing.JCheckBox;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.LayoutStyle.ComponentPlacement;
-import javax.swing.SwingUtilities;
-import javax.swing.text.JTextComponent;
-
-import org.jfree.chart.ChartFactory;
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.axis.NumberAxis;
-import org.jfree.chart.renderer.xy.XYItemRenderer;
-import org.jfree.data.time.FixedMillisecond;
-import org.jfree.data.time.RegularTimePeriod;
-import org.jfree.data.time.TimeSeries;
-import org.jfree.data.time.TimeSeriesCollection;
-
-import com.redhat.thermostat.client.core.views.HostMemoryView;
-import com.redhat.thermostat.client.internal.ui.swing.WrapLayout;
-import com.redhat.thermostat.client.locale.LocaleResources;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.model.DiscreteTimeData;
-import com.redhat.thermostat.common.utils.DisplayableValues;
-import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
-
-public class HostMemoryPanel extends HostMemoryView implements SwingComponent {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private JPanel visiblePanel;
-
-    private final MemoryCheckboxListener memoryCheckboxListener = new MemoryCheckboxListener();
-
-    private final JTextComponent totalMemory = new ValueField("${TOTAL_MEMORY}");
-
-    private final JPanel memoryCheckBoxPanel = new JPanel(new WrapLayout(FlowLayout.LEADING));
-    private final CopyOnWriteArrayList<GraphVisibilityChangeListener> listeners = new CopyOnWriteArrayList<>();
-    private final TimeSeriesCollection memoryCollection = new TimeSeriesCollection();
-    private final Map<String, TimeSeries> dataset = new HashMap<>();
-    private final Map<String, JCheckBox> checkBoxes = new HashMap<>();
-    private final Map<String, Color> colors = new HashMap<>();
-
-    private JFreeChart chart;
-
-    public HostMemoryPanel() {
-        super();
-        initializePanel();
-
-        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
-            @Override
-            public void componentShown(Component component) {
-                notifier.fireAction(Action.VISIBLE);
-            }
-            @Override
-            public void componentHidden(Component component) {
-                notifier.fireAction(Action.HIDDEN);
-            }
-        });
-    }
-
-    @Override
-    public void setTotalMemory(final String newValue) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                totalMemory.setText(newValue);
-            }
-        });
-    }
-
-    @Override
-    public Component getUiComponent() {
-        return visiblePanel;
-    }
-
-    @Override
-    public void addMemoryChart(final String tag, final String humanReadableName) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                int colorIndex = colors.size();
-                colors.put(tag, ChartColors.getColor(colorIndex));
-                TimeSeries series = new TimeSeries(tag);
-                dataset.put(tag, series);
-                JCheckBox newCheckBox = new JCheckBox(createLabelWithLegend(humanReadableName, colors.get(tag)));
-                newCheckBox.setActionCommand(tag);
-                newCheckBox.setSelected(true);
-                newCheckBox.addActionListener(memoryCheckboxListener);
-                newCheckBox.setOpaque(false);
-                checkBoxes.put(tag, newCheckBox);
-                memoryCheckBoxPanel.add(newCheckBox);
-
-                updateColors();
-            }
-        });
-
-    }
-
-    private String createLabelWithLegend(String text, Color color) {
-        String hexColor = "#" + Integer.toHexString(color.getRGB() & 0x00ffffff);
-        return "<html> <font color='" + hexColor + "'>\u2588</font> " + text + "</html>";
-    }
-
-    @Override
-    public void removeMemoryChart(final String tag) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                TimeSeries series = dataset.remove(tag);
-                memoryCollection.removeSeries(series);
-                JCheckBox box = checkBoxes.remove(tag);
-                memoryCheckBoxPanel.remove(box);
-
-                updateColors();
-            }
-        });
-    }
-
-    @Override
-    public void showMemoryChart(final String tag) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                TimeSeries series = dataset.get(tag);
-                memoryCollection.addSeries(series);
-
-                updateColors();
-            }
-        });
-    }
-
-    @Override
-    public void hideMemoryChart(final String tag) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                TimeSeries series = dataset.get(tag);
-                memoryCollection.removeSeries(series);
-
-                updateColors();
-            }
-        });
-    }
-
-    @Override
-    public void addMemoryData(final String tag, List<DiscreteTimeData<? extends Number>> data) {
-        final List<DiscreteTimeData<? extends Number>> copy = new ArrayList<>(data);
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                final TimeSeries series = dataset.get(tag);
-                for (DiscreteTimeData<? extends Number> timeData: copy) {
-                    RegularTimePeriod period = new FixedMillisecond(timeData.getTimeInMillis());
-                    if (series.getDataItem(period) == null) {
-                        Long sizeInBytes = (Long) timeData.getData();
-                        Double sizeInMegaBytes = DisplayableValues.Scale.convertTo(Scale.MiB, sizeInBytes);
-                        series.add(new FixedMillisecond(timeData.getTimeInMillis()), sizeInMegaBytes, false);
-                    }
-                }
-                series.fireSeriesChanged();
-            }
-        });
-    }
-
-    @Override
-    public void clearMemoryData(final String tag) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                TimeSeries series = dataset.get(tag);
-                series.clear();
-            }
-        });
-    }
-
-    @Override
-    public void addGraphVisibilityListener(GraphVisibilityChangeListener listener) {
-        listeners.add(listener);
-    }
-
-    @Override
-    public void removeGraphVisibilityListener(GraphVisibilityChangeListener listener) {
-        listeners.remove(listener);
-    }
-
-    @Override
-    public void addActionListener(ActionListener<Action> listener) {
-        notifier.addActionListener(listener);
-    }
-
-    @Override
-    public void removeActionListener(ActionListener<Action> listener) {
-        notifier.removeActionListener(listener);
-    }
-
-    private void initializePanel() {
-        visiblePanel = new JPanel();
-        visiblePanel.setOpaque(false);
-
-        chart = createMemoryChart();
-
-        JPanel chartPanel = new RecentTimeSeriesChartPanel(new RecentTimeSeriesChartController(chart));
-        chartPanel.setOpaque(false);
-
-        JLabel lblMemory = Components.header(translator.localize(LocaleResources.HOST_MEMORY_SECTION_OVERVIEW));
-
-        JLabel totalMemoryLabel = Components.label(translator.localize(LocaleResources.HOST_INFO_MEMORY_TOTAL));
-
-        memoryCheckBoxPanel.setOpaque(false);
-
-        GroupLayout groupLayout = new GroupLayout(visiblePanel);
-        groupLayout.setHorizontalGroup(
-            groupLayout.createParallelGroup(Alignment.LEADING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addContainerGap()
-                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
-                        .addComponent(chartPanel, GroupLayout.DEFAULT_SIZE, 883, Short.MAX_VALUE)
-                        .addGroup(groupLayout.createSequentialGroup()
-                            .addGap(12)
-                            .addComponent(totalMemoryLabel)
-                            .addPreferredGap(ComponentPlacement.RELATED)
-                            .addComponent(totalMemory, GroupLayout.DEFAULT_SIZE, 751, Short.MAX_VALUE))
-                        .addComponent(lblMemory)
-                        .addComponent(memoryCheckBoxPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE))
-                    .addContainerGap())
-        );
-        groupLayout.setVerticalGroup(
-            groupLayout.createParallelGroup(Alignment.LEADING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addContainerGap()
-                    .addComponent(lblMemory)
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
-                        .addComponent(totalMemory, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                        .addComponent(totalMemoryLabel))
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addComponent(chartPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addComponent(memoryCheckBoxPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
-                    .addContainerGap())
-        );
-        visiblePanel.setLayout(groupLayout);
-    }
-
-    private JFreeChart createMemoryChart() {
-        JFreeChart chart = ChartFactory.createTimeSeriesChart(
-                translator.localize(LocaleResources.HOST_MEMORY_CHART_TITLE), // Title
-                translator.localize(LocaleResources.HOST_MEMORY_CHART_TIME_LABEL), // x-axis Label
-                translator.localize(LocaleResources.HOST_MEMORY_CHART_SIZE_LABEL, Scale.MiB.name()), // y-axis Label
-                memoryCollection, // Dataset
-                false, // Show Legend
-                false, // Use tooltips
-                false // Configure chart to generate URLs?
-                );
-
-        chart.getPlot().setBackgroundPaint( new Color(255,255,255,0) );
-        chart.getPlot().setBackgroundImageAlpha(0.0f);
-        chart.getPlot().setOutlinePaint(new Color(0,0,0,0));
-
-        NumberAxis rangeAxis = (NumberAxis) chart.getXYPlot().getRangeAxis();
-        rangeAxis.setAutoRangeMinimumSize(100);
-
-        return chart;
-    }
-
-    private void fireShowHideHandlers(boolean show, String tag) {
-        for (GraphVisibilityChangeListener listener: listeners) {
-            if (show) {
-                listener.show(tag);
-            } else {
-                listener.hide(tag);
-            }
-        }
-    }
-
-    /**
-     * Adding or removing series to the series collection may change the order
-     * of existing items. Plus the paint for the index is now out-of-date. So
-     * let's walk through all the series and set the right paint for those.
-     */
-    private void updateColors() {
-        XYItemRenderer itemRenderer = chart.getXYPlot().getRenderer();
-        for (int i = 0; i < memoryCollection.getSeriesCount(); i++) {
-            String tag = (String) memoryCollection.getSeriesKey(i);
-            Color color = colors.get(tag);
-            itemRenderer.setSeriesPaint(i, color);
-        }
-    }
-
-    private class MemoryCheckboxListener implements java.awt.event.ActionListener {
-        @Override
-        public void actionPerformed(java.awt.event.ActionEvent e) {
-            JCheckBox source = (JCheckBox) e.getSource();
-            fireShowHideHandlers(source.isSelected(), source.getActionCommand());
-        }
-
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/HostOverviewPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,306 +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.ui;
-
-import java.awt.Component;
-
-import javax.swing.JPanel;
-import javax.swing.JTable;
-import javax.swing.SwingUtilities;
-import javax.swing.table.DefaultTableModel;
-import javax.swing.table.JTableHeader;
-
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.core.views.HostOverviewView;
-import com.redhat.thermostat.client.locale.LocaleResources;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.locale.Translate;
-
-import javax.swing.GroupLayout;
-import javax.swing.GroupLayout.Alignment;
-import javax.swing.LayoutStyle.ComponentPlacement;
-import java.awt.BorderLayout;
-
-public class HostOverviewPanel extends HostOverviewView implements SwingComponent {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private JPanel visiblePanel;
-
-    private final ValueField hostname = new ValueField("${hostname}");
-    private final ValueField cpuModel = new ValueField("${cpu-model}");
-    private final ValueField cpuCount = new ValueField("${cpu-count}");
-    private final ValueField totalMemory = new ValueField("${total-memory}");
-    private final ValueField osName = new ValueField("${os-name}");
-    private final ValueField osKernel = new ValueField("${os-kernel}");
-
-    private final DefaultTableModel networkTableModel = new DefaultTableModel() {
-        @Override
-        public boolean isCellEditable(int row, int column) {
-            return false;
-        }
-    };
-
-    private Object[] networkTableColumns;
-    private Object[][] networkTableData;
-
-    public HostOverviewPanel() {
-        super();
-        initializePanel();
-
-        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
-            @Override
-            public void componentShown(Component component) {
-                notifier.fireAction(Action.VISIBLE);
-            }
-
-            @Override
-            public void componentHidden(Component component) {
-                notifier.fireAction(Action.HIDDEN);
-            }
-        });
-    }
-
-    @Override
-    public void addActionListener(ActionListener<Action> listener) {
-        notifier.addActionListener(listener);
-    }
-
-    @Override
-    public void removeActionListener(ActionListener<Action> listener) {
-        notifier.removeActionListener(listener);
-    }
-
-    @Override
-    public void setHostName(final String newHostName) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                hostname.setText(newHostName);
-            }
-        });
-    }
-
-    @Override
-    public void setCpuModel(final String newCpuModel) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                cpuModel.setText(newCpuModel);
-            }
-        });
-    }
-
-    @Override
-    public void setCpuCount(final String newCpuCount) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                cpuCount.setText(newCpuCount);
-            }
-        });
-    }
-
-    @Override
-    public void setTotalMemory(final String newTotalMemory) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                totalMemory.setText(newTotalMemory);
-            }
-        });
-    }
-
-    @Override
-    public void setOsName(final String newOsName) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                osName.setText(newOsName);
-            }
-        });
-    }
-
-    @Override
-    public void setOsKernel(final String newOsKernel) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                osKernel.setText(newOsKernel);
-            }
-        });
-    }
-
-    @Override
-    public void setNetworkTableColumns(final Object[] columns) {
-        this.networkTableColumns = columns;
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                networkTableModel.setColumnIdentifiers(networkTableColumns);
-            }
-        });
-    }
-
-    @Override
-    public void setInitialNetworkTableData(final Object[][] data) {
-        this.networkTableData = data;
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                networkTableModel.setDataVector(networkTableData, networkTableColumns);
-            }
-        });
-    }
-
-    @Override
-    public void updateNetworkTableData(final int row, final int column, final String data) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                networkTableModel.setValueAt(data, row, column);
-            }
-        });
-    }
-
-    @Override
-    public Component getUiComponent() {
-        return visiblePanel;
-    }
-
-    private void initializePanel() {
-        visiblePanel = new JPanel();
-        SectionHeader overviewSection = new SectionHeader(translator.localize(LocaleResources.HOST_OVERVIEW_SECTION_BASICS));
-        LabelField hostnameLabel = new LabelField(translator.localize(LocaleResources.HOST_INFO_HOSTNAME));
-        SectionHeader hardwareSection = new SectionHeader(translator.localize(LocaleResources.HOST_OVERVIEW_SECTION_HARDWARE));
-        LabelField cpuModelLabel = new LabelField(translator.localize(LocaleResources.HOST_INFO_CPU_MODEL));
-        LabelField cpuCountLabel = new LabelField(translator.localize(LocaleResources.HOST_INFO_CPU_COUNT));
-        LabelField memoryTotalLabel = new LabelField(translator.localize(LocaleResources.HOST_INFO_MEMORY_TOTAL));
-        LabelField networkLabel = new LabelField(translator.localize(LocaleResources.HOST_INFO_NETWORK));
-        SectionHeader softwareSection = new SectionHeader(translator.localize(LocaleResources.HOST_OVERVIEW_SECTION_SOFTWARE));
-        LabelField osNameLabel = new LabelField(translator.localize(LocaleResources.HOST_INFO_OS_NAME));
-        LabelField osKernelLabel = new LabelField(translator.localize(LocaleResources.HOST_INFO_OS_KERNEL));
-
-        JPanel panel = new JPanel();
-
-        GroupLayout gl_visiblePanel = new GroupLayout(visiblePanel);
-        gl_visiblePanel.setHorizontalGroup(
-            gl_visiblePanel.createParallelGroup(Alignment.LEADING)
-                .addGroup(gl_visiblePanel.createSequentialGroup()
-                    .addContainerGap()
-                    .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING)
-                        .addComponent(hardwareSection, GroupLayout.DEFAULT_SIZE, 620, Short.MAX_VALUE)
-                        .addComponent(overviewSection, GroupLayout.DEFAULT_SIZE, 620, Short.MAX_VALUE)
-                        .addGroup(gl_visiblePanel.createSequentialGroup()
-                            .addGroup(gl_visiblePanel.createParallelGroup(Alignment.TRAILING, false)
-                                .addGroup(gl_visiblePanel.createSequentialGroup()
-                                    .addGap(12)
-                                    .addComponent(hostnameLabel, GroupLayout.DEFAULT_SIZE, 134, Short.MAX_VALUE))
-                                .addComponent(cpuCountLabel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                                .addComponent(cpuModelLabel, GroupLayout.DEFAULT_SIZE, 134, Short.MAX_VALUE)
-                                .addComponent(memoryTotalLabel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                                .addGroup(gl_visiblePanel.createSequentialGroup()
-                                    .addGap(12)
-                                    .addComponent(networkLabel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
-                            .addPreferredGap(ComponentPlacement.RELATED)
-                            .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING)
-                                .addComponent(panel, GroupLayout.DEFAULT_SIZE, 462, Short.MAX_VALUE)
-                                .addComponent(cpuCount, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                                .addComponent(cpuModel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                                .addComponent(hostname, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                                .addComponent(totalMemory, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
-                        .addComponent(softwareSection, GroupLayout.DEFAULT_SIZE, 620, Short.MAX_VALUE)
-                        .addGroup(gl_visiblePanel.createSequentialGroup()
-                            .addGap(12)
-                            .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING, false)
-                                .addComponent(osKernelLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                                .addComponent(osNameLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 129, Short.MAX_VALUE))
-                            .addPreferredGap(ComponentPlacement.RELATED)
-                            .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING)
-                                .addComponent(osKernel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                                .addComponent(osName, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
-                    .addContainerGap())
-        );
-        gl_visiblePanel.setVerticalGroup(
-            gl_visiblePanel.createParallelGroup(Alignment.LEADING)
-                .addGroup(gl_visiblePanel.createSequentialGroup()
-                    .addContainerGap()
-                    .addComponent(overviewSection, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING, false)
-                        .addComponent(hostname, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE)
-                        .addComponent(hostnameLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
-                    .addPreferredGap(ComponentPlacement.UNRELATED)
-                    .addComponent(hardwareSection, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING, false)
-                        .addComponent(cpuModelLabel, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE)
-                        .addComponent(cpuModel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING, false)
-                        .addComponent(cpuCountLabel, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE)
-                        .addComponent(cpuCount, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING)
-                        .addComponent(memoryTotalLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                        .addComponent(totalMemory, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING)
-                        .addComponent(networkLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                        .addComponent(panel, GroupLayout.PREFERRED_SIZE, 109, GroupLayout.PREFERRED_SIZE))
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addComponent(softwareSection, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING)
-                        .addComponent(osNameLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                        .addComponent(osName, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING)
-                        .addComponent(osKernelLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
-                        .addComponent(osKernel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
-                    .addGap(128))
-        );
-
-        panel.setLayout(new BorderLayout(0, 0));
-
-        JTable networkTable = new JTable(networkTableModel);
-        panel.add(networkTable);
-        JTableHeader header = networkTable.getTableHeader();
-        panel.add(header, BorderLayout.PAGE_START);
-        visiblePanel.setLayout(gl_visiblePanel);
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/HtmlTextBuilder.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,118 +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.ui;
-
-public class HtmlTextBuilder {
-
-    /*
-     * The api provided by this class needs to be cleaned up.
-     */
-
-    private final StringBuilder text = new StringBuilder();
-
-    public HtmlTextBuilder() {
-        // do nothing
-    }
-
-    public HtmlTextBuilder(String text) {
-        text = escape(text);
-        this.text.append(text);
-    }
-
-    public HtmlTextBuilder bold(boolean on) {
-        if (on) {
-            this.text.append("<b>");
-        } else {
-            this.text.append("</b>");
-        }
-        return this;
-    }
-
-    public HtmlTextBuilder bold(String toBold) {
-        text.append("<b>").append(toBold).append("</b>");
-        return this;
-    }
-
-    public HtmlTextBuilder larger(String toAppend) {
-        text.append("<font size='+2'>").append(escape(toAppend)).append("</font>");
-        return this;
-    }
-
-    public HtmlTextBuilder huge(String toAppend) {
-        text.append("<font size='+6'>").append(escape(toAppend)).append("</font>");
-        return this;
-    }
-
-    @Override
-    public String toString() {
-        // FIXME
-        return null;
-    }
-
-    public String toHtml() {
-        return "<html>" + text.toString() + "</html>";
-    }
-
-    public String toPartialHtml() {
-        return text.toString();
-    }
-
-    private static String escape(String toEscape) {
-        // FIXME implement this
-        return toEscape;
-    }
-
-    public HtmlTextBuilder append(String toAppend) {
-        text.append(escape(toAppend));
-        return this;
-    }
-
-    public HtmlTextBuilder appendRaw(String toAppend) {
-        text.append(toAppend);
-        return this;
-    }
-
-    public static String boldHtml(String toBold) {
-        return new HtmlTextBuilder().bold(toBold).toHtml();
-    }
-
-    public HtmlTextBuilder newLine() {
-        text.append("<br>");
-        return this;
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/IconResource.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +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.ui;
-
-import java.io.File;
-
-import javax.swing.Icon;
-import javax.swing.ImageIcon;
-
-public class IconResource {
-    /* FIXME we need to pick up the icons dynamically */
-
-    private static final String ICON_PREFIX = "/usr/share/icons/gnome/";
-
-    // an icon that should always be available and indicate that the actual icon
-    // is missing.
-    public static final IconResource MISSING_ICON = null;
-
-    public static final IconResource JAVA_APPLICATION = new IconResource("duke.png");
-    public static final IconResource HOST = new IconResource(ICON_PREFIX + "16x16/devices/computer.png");
-    
-    public static final IconResource ERROR = new IconResource(ICON_PREFIX + "48x48/status/dialog-error.png");
-    public static final IconResource QUESTION = new IconResource(ICON_PREFIX + "48x48/status/dialog-question.png");
-    public static final IconResource WARNING = new IconResource(ICON_PREFIX + "48x48/status/dialog-warning.png");
-
-    public static final IconResource COMPUTER = new IconResource(ICON_PREFIX + "48x48/devices/computer.png");
-    public static final IconResource NETWORK_SERVER = new IconResource(ICON_PREFIX + "48x48/places/network-server.png");
-    public static final IconResource NETWORK_GROUP = new IconResource(ICON_PREFIX + "48x48/places/network-workgroup.png");
-
-    public static final IconResource ARROW_RIGHT = new IconResource(ICON_PREFIX + "48x48/actions/go-next.png");
-
-    public static final IconResource SEARCH = new IconResource(ICON_PREFIX + "16x16/actions/search.png");
-
-    private final String path;
-
-    private IconResource(String descriptor) {
-        this.path = descriptor;
-    }
-
-    public static IconResource fromPath(String path) {
-        // TODO implement this
-        return null;
-    }
-
-    public Icon getIcon() {
-        if (new File(path).exists()) {
-            return new ImageIcon(path);
-        }
-        return null;
-    }
-
-    public String getPath() {
-        return path;
-    }
-
-    public String getUrl() {
-        return "file:" + getPath();
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/LabelField.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.ui;
-
-import javax.swing.JLabel;
-import javax.swing.SwingConstants;
-
-public class LabelField extends JLabel {
-
-    public LabelField(String text) {
-        super(text);
-        setHorizontalAlignment(SwingConstants.TRAILING);
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/LayoutDebugHelper.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +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.ui;
-
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Window;
-
-import javax.swing.BorderFactory;
-import javax.swing.JComponent;
-
-/**
- * This class goes through the swing container hierarchy and adds random colored
- * borders to the components themselves. it makes it easier to see what the
- * {@code LayoutManager}s are doing
- */
-public class LayoutDebugHelper {
-
-    private Color[] colors = new Color[] { Color.BLACK, Color.BLUE, Color.CYAN, Color.GREEN, Color.MAGENTA, Color.PINK, Color.ORANGE, Color.RED, Color.YELLOW };
-    private int colorIndex = 0;
-
-    public void debugLayout(Window w) {
-        Component[] children = w.getComponents();
-        debugLayout(children);
-    }
-
-    public void debugLayout(Component c) {
-        if (c instanceof JComponent) {
-            JComponent panel = (JComponent) c;
-            try {
-                panel.setBorder(BorderFactory.createLineBorder(colors[colorIndex % colors.length]));
-            } catch (IllegalArgumentException iae) {
-                // never mind then
-            }
-            colorIndex++;
-            debugLayout(panel.getComponents());
-        }
-    }
-
-    public void debugLayout(Component[] components) {
-        for (Component aComponent : components) {
-            debugLayout(aComponent);
-        }
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/MainWindow.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,790 +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.ui;
-
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.awt.Graphics2D;
-import java.awt.event.ComponentAdapter;
-import java.awt.event.ComponentEvent;
-import java.awt.event.InputEvent;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.awt.image.BufferedImage;
-import java.io.PrintStream;
-import java.lang.reflect.InvocationTargetException;
-import java.nio.ByteBuffer;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-
-import javax.swing.BorderFactory;
-import javax.swing.Icon;
-import javax.swing.ImageIcon;
-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JFrame;
-import javax.swing.JMenu;
-import javax.swing.JMenuBar;
-import javax.swing.JMenuItem;
-import javax.swing.JPanel;
-import javax.swing.JPopupMenu;
-import javax.swing.JScrollPane;
-import javax.swing.JSplitPane;
-import javax.swing.JTree;
-import javax.swing.KeyStroke;
-import javax.swing.SwingUtilities;
-import javax.swing.SwingWorker;
-import javax.swing.ToolTipManager;
-import javax.swing.event.TreeExpansionEvent;
-import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.TreeSelectionListener;
-import javax.swing.event.TreeWillExpandListener;
-import javax.swing.tree.DefaultMutableTreeNode;
-import javax.swing.tree.DefaultTreeCellRenderer;
-import javax.swing.tree.DefaultTreeModel;
-import javax.swing.tree.ExpandVetoException;
-import javax.swing.tree.TreeNode;
-import javax.swing.tree.TreePath;
-import javax.swing.tree.TreeSelectionModel;
-
-import sun.misc.Signal;
-
-import com.redhat.thermostat.client.core.HostFilter;
-import com.redhat.thermostat.client.core.VmFilter;
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.internal.MainView;
-import com.redhat.thermostat.client.locale.LocaleResources;
-import com.redhat.thermostat.client.osgi.service.HostDecorator;
-import com.redhat.thermostat.client.osgi.service.MenuAction;
-import com.redhat.thermostat.client.osgi.service.VmDecorator;
-import com.redhat.thermostat.client.osgi.service.VMContextAction;
-import com.redhat.thermostat.client.ui.SearchFieldView.SearchAction;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.ActionNotifier;
-import com.redhat.thermostat.common.HostsVMsLoader;
-import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.common.dao.Ref;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.utils.StringUtils;
-import com.redhat.thermostat.swing.EdtHelper;
-import com.redhat.thermostat.swing.StatusBar;
-
-public class MainWindow extends JFrame implements MainView {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    /**
-     * Updates a TreeModel in the background in an Swing EDT-safe manner.
-     */
-    private static class BackgroundTreeModelWorker extends SwingWorker<DefaultMutableTreeNode, Void> {
-
-        private JTree tree;
-
-        private final DefaultTreeModel treeModel;
-        private DefaultMutableTreeNode treeRoot;
-        
-        private List<HostFilter> hostFilters;
-        private List<VmFilter> vmFilters;
-        private List<HostDecorator> hostDecorators;
-        private List<VmDecorator> vmDecorators;
-        
-        private HostsVMsLoader hostsVMsLoader;
-
-        public BackgroundTreeModelWorker(DefaultTreeModel model, DefaultMutableTreeNode root,
-                                         List<HostFilter> hostFilters, List<VmFilter> vmFilters,
-                                         List<HostDecorator> hostDecorators, List<VmDecorator> vmDecorators,
-                                         HostsVMsLoader hostsVMsLoader, JTree tree)
-        {
-            this.hostFilters = hostFilters;
-            this.vmFilters = vmFilters;
-
-            this.vmDecorators = vmDecorators;
-            this.hostDecorators = hostDecorators;
-
-            this.treeModel = model;
-            this.treeRoot = root;
-            this.hostsVMsLoader = hostsVMsLoader;
-            this.tree = tree;
-        }
-
-        @Override
-        protected DefaultMutableTreeNode doInBackground() throws Exception {
-            DefaultMutableTreeNode root = new DefaultMutableTreeNode();
-            
-            Collection<HostRef> hostsInRemoteModel = hostsVMsLoader.getHosts();
-            buildHostSubTree(root, hostsInRemoteModel);
-            return root;
-        }
-
-        private boolean buildHostSubTree(DefaultMutableTreeNode parent, Collection<HostRef> objectsInRemoteModel) {
-            boolean subTreeMatches = false;
-            for (HostRef inRemoteModel : objectsInRemoteModel) {
-                DecoratedDefaultMutableTreeNode inTreeNode =
-                        new DecoratedDefaultMutableTreeNode(inRemoteModel);
-
-                boolean shouldInsert = false;
-                if (hostFilters == null) {
-                    shouldInsert = true;
-                } else {
-                    shouldInsert = true;
-                    for (HostFilter filter : hostFilters) {
-                        if (!filter.matches(inRemoteModel)) {
-                            shouldInsert = false;
-                            break;
-                        }
-                    }
-                }
-                
-                Collection<VmRef> children = hostsVMsLoader.getVMs(inRemoteModel);
-                boolean subtreeResult = buildVmSubTree(inTreeNode, children);
-                if (subtreeResult) {
-                    shouldInsert = true;
-                }
-
-                if (shouldInsert) {
-                    for (HostDecorator decorator : hostDecorators) {
-                        HostFilter filter = decorator.getFilter();
-                        if (filter != null && filter.matches(inRemoteModel)) {
-                            inTreeNode.addDecorator(decorator.getDecorator());
-                        }
-                    }
-                    
-                    parent.add(inTreeNode);
-                    subTreeMatches = true;
-                }
-            }
-            
-            return subTreeMatches;
-        }
-
-        private boolean buildVmSubTree(DefaultMutableTreeNode parent, Collection<VmRef> objectsInRemoteModel) {
-            boolean subTreeMatches = false;
-            for (VmRef inRemoteModel : objectsInRemoteModel) {
-                DecoratedDefaultMutableTreeNode inTreeNode =
-                        new DecoratedDefaultMutableTreeNode(inRemoteModel);
-
-                boolean shouldInsert = false;
-                if (vmFilters == null) {
-                    shouldInsert = true;
-                } else {
-                    shouldInsert = true;
-                    for (VmFilter filter : vmFilters) {
-                        if (!filter.matches(inRemoteModel)) {
-                            shouldInsert = false;
-                            break;
-                        }
-                    }
-                }
-
-                if (shouldInsert) {
-                    for (VmDecorator decorator : vmDecorators) {
-                        VmFilter filter = decorator.getFilter();
-                        if (filter != null && filter.matches(inRemoteModel)) {
-                            inTreeNode.addDecorator(decorator.getDecorator());
-                        }
-                    }
-
-                    parent.add(inTreeNode);
-                    subTreeMatches = true;
-                }
-            }
-
-            return subTreeMatches;
-        }
-
-        @Override
-        protected void done() {
-            DefaultMutableTreeNode sourceRoot;
-            try {
-                sourceRoot = get();
-                syncTree(sourceRoot, treeModel, treeRoot);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            } catch (ExecutionException e) {
-                e.printStackTrace();
-            }
-        }
-
-        private void syncTree(DefaultMutableTreeNode sourceRoot, DefaultTreeModel targetModel, DefaultMutableTreeNode targetNode) {
-            
-            @SuppressWarnings("unchecked") // We know what we put into these trees.
-            List<DefaultMutableTreeNode> sourceChildren = Collections.list(sourceRoot.children());
-
-            @SuppressWarnings("unchecked")
-            List<DefaultMutableTreeNode> targetChildren = Collections.list(targetNode.children());
-            for (DefaultMutableTreeNode sourceChild : sourceChildren) {
-                Ref sourceRef = (Ref) sourceChild.getUserObject();
-                DefaultMutableTreeNode targetChild = null;
-                for (DefaultMutableTreeNode aChild : targetChildren) {
-                    Ref targetRef = (Ref) aChild.getUserObject();
-                    if (targetRef.equals(sourceRef)) {
-                        targetChild = aChild;
-                        if (sourceChild instanceof DecoratedDefaultMutableTreeNode) {
-                            DecoratedDefaultMutableTreeNode source = (DecoratedDefaultMutableTreeNode) sourceChild;
-                            ((DecoratedDefaultMutableTreeNode) targetChild).setDecorators(source.getDecorators());
-                        }
-                        break;
-                    }
-                }
-
-                if (targetChild == null) {
-                    targetChild = new DecoratedDefaultMutableTreeNode(sourceRef);
-                    if (sourceChild instanceof DecoratedDefaultMutableTreeNode) {
-                        DecoratedDefaultMutableTreeNode source = (DecoratedDefaultMutableTreeNode) sourceChild;
-                        ((DecoratedDefaultMutableTreeNode) targetChild).setDecorators(source.getDecorators());
-                    }
-                    targetModel.insertNodeInto(targetChild, targetNode, targetNode.getChildCount());
-                }
-
-                syncTree(sourceChild, targetModel, targetChild);
-            }
-
-            for (DefaultMutableTreeNode targetChild : targetChildren) {
-                Ref targetRef = (Ref) targetChild.getUserObject();
-                boolean matchFound = false;
-                for (DefaultMutableTreeNode sourceChild : sourceChildren) {
-                    Ref sourceRef = (Ref) sourceChild.getUserObject();
-                    if (targetRef.equals(sourceRef)) {
-                        matchFound = true;
-                        break;
-                    }
-                }
-
-                if (!matchFound) {
-                    targetModel.removeNodeFromParent(targetChild);
-                }
-            }
-            ensureRootIsExpanded(targetModel);
-        }
-
-        private void ensureRootIsExpanded(final DefaultTreeModel model) {
-            DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
-            tree.expandPath(new TreePath(root.getPath()));
-        }
-
-    }
-
-    private static final long serialVersionUID = 5608972421496808177L;
-
-    private final JMenuBar mainMenuBar = new JMenuBar();
-    private final MenuHelper mainMenuHelper = new MenuHelper(mainMenuBar);
-    private JPanel contentArea = null;
-
-    private SearchFieldSwingView searchField = new SearchFieldSwingView();
-    private JTree agentVmTree = null;
-
-    private final ShutdownClient shutdownAction;
-
-    private ActionNotifier<Action> actionNotifier = new ActionNotifier<>(this);
-
-    private JPopupMenu vmContextMenu;
-    private StatusBar statusBar;
-    
-    private final DefaultMutableTreeNode publishedRoot =
-            new DefaultMutableTreeNode(translator.localize(LocaleResources.MAIN_WINDOW_TREE_ROOT_NAME));
-    private final DefaultTreeModel publishedTreeModel = new DefaultTreeModel(publishedRoot);
-
-    @SuppressWarnings("restriction")
-    public MainWindow() {
-        super();
-
-        shutdownAction = new ShutdownClient();
-
-        searchField.addActionListener(new ActionListener<SearchAction>() {
-            @Override
-            public void actionPerformed(ActionEvent<SearchAction> actionEvent) {
-                switch (actionEvent.getActionId()) {
-                case TEXT_CHANGED:
-                    fireViewAction(Action.HOST_VM_TREE_FILTER);
-                    break;
-                }
-            }
-        });
-        agentVmTree = new JTree(publishedTreeModel);
-        agentVmTree.setName("agentVmTree");
-        agentVmTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
-        agentVmTree.setCellRenderer(new AgentVmTreeCellRenderer());
-        agentVmTree.addTreeWillExpandListener(new TreeWillExpandListener() {
-            @Override
-            public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
-                /* Yup, tree will expand */
-            }
-
-            @Override
-            public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
-                if (new TreePath(publishedRoot.getPath()).equals(event.getPath())) {
-                    throw new ExpandVetoException(event, "root cant be collapsed");
-                }
-            }
-        });
-        ToolTipManager.sharedInstance().registerComponent(agentVmTree);
-        contentArea = new JPanel(new BorderLayout());
-
-        setupMenus();
-        setupPanels();
-
-        this.setPreferredSize(new Dimension(800, 600));
-
-        agentVmTree.setSelectionPath(new TreePath(((DefaultMutableTreeNode) publishedTreeModel.getRoot()).getPath()));
-        
-        //agentVmTree.setLargeModel(true);
-        agentVmTree.setRowHeight(25);
-        
-        statusBar = new StatusBar();
-        getContentPane().add(statusBar, BorderLayout.SOUTH);
-        
-        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
-        addWindowListener(shutdownAction);
-
-        // Handle SIGTERM/SIGINT properly
-        Signal.handle(new Signal("TERM"), shutdownAction);
-        Signal.handle(new Signal("INT"), shutdownAction);
-        
-        addComponentListener(new ComponentAdapter() {
-
-            @Override
-            public void componentShown(ComponentEvent e) {
-                fireViewAction(Action.VISIBLE);
-            }
-
-            @Override
-            public void componentHidden(ComponentEvent e) {
-                fireViewAction(Action.HIDDEN);
-            }
-        });
-
-    }
-
-    private void setupMenus() {
-
-        JMenu fileMenu = new JMenu(translator.localize(LocaleResources.MENU_FILE));
-        fileMenu.getPopupMenu().setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1));
-        mainMenuBar.add(fileMenu);
-
-        JMenuItem fileExitMenu = new JMenuItem(translator.localize(LocaleResources.MENU_FILE_EXIT));
-        fileExitMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, InputEvent.CTRL_DOWN_MASK));
-        fileExitMenu.addActionListener(shutdownAction);
-        fileMenu.add(fileExitMenu);
-
-        JMenu editMenu = new JMenu(translator.localize(LocaleResources.MENU_EDIT));
-        mainMenuBar.add(editMenu);
-
-        JMenuItem configureClientMenuItem = new JMenuItem(translator.localize(LocaleResources.MENU_EDIT_CONFIGURE_CLIENT));
-        configureClientMenuItem.setName("showClientConfig");
-        configureClientMenuItem.addActionListener(new java.awt.event.ActionListener() {
-            @Override
-            public void actionPerformed(java.awt.event.ActionEvent e) {
-                fireViewAction(Action.SHOW_CLIENT_CONFIG);
-            }
-        });
-        editMenu.add(configureClientMenuItem);
-
-        editMenu.addSeparator();
-        JMenuItem historyModeMenuItem = new JCheckBoxMenuItem(translator.localize(LocaleResources.MENU_EDIT_ENABLE_HISTORY_MODE));
-        historyModeMenuItem.setName("historyModeSwitch");
-        historyModeMenuItem.setSelected(false);
-        historyModeMenuItem.addActionListener(new java.awt.event.ActionListener() {
-            @Override
-            public void actionPerformed(java.awt.event.ActionEvent e) {
-                fireViewAction(Action.SWITCH_HISTORY_MODE);
-            }
-        });
-        editMenu.add(historyModeMenuItem);
-
-        JMenu viewMenu = new JMenu(translator.localize(LocaleResources.MENU_VIEW));
-        mainMenuBar.add(viewMenu);
-        JMenuItem configureAgentMenuItem = new JMenuItem(translator.localize(LocaleResources.MENU_VIEW_AGENTS));
-        configureAgentMenuItem.setName("showAgentConfig");
-        configureAgentMenuItem.addActionListener(new java.awt.event.ActionListener() {
-            @Override
-            public void actionPerformed(java.awt.event.ActionEvent e) {
-                fireViewAction(Action.SHOW_AGENT_CONFIG);
-            }
-        });
-        viewMenu.add(configureAgentMenuItem);
-
-        JMenu helpMenu = new JMenu(translator.localize(LocaleResources.MENU_HELP));
-        helpMenu.getPopupMenu().setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1));
-        mainMenuBar.add(helpMenu);
-
-        JMenuItem helpAboutMenu = new JMenuItem(translator.localize(LocaleResources.MENU_HELP_ABOUT));
-        helpAboutMenu.addActionListener(new java.awt.event.ActionListener() {
-            @Override
-            public void actionPerformed(java.awt.event.ActionEvent e) {
-                fireViewAction(Action.SHOW_ABOUT_DIALOG);
-            }
-        });
-        helpMenu.add(helpAboutMenu);
-        setJMenuBar(mainMenuBar);
-    }
-
-    private void setupPanels() {
-        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
-        splitPane.setOneTouchExpandable(true);
-        
-        JPanel navigationPanel = new JPanel(new BorderLayout());
-
-        navigationPanel.add(searchField, BorderLayout.PAGE_START);
-
-        agentVmTree.addTreeSelectionListener(new TreeSelectionListener() {
-            @Override
-            public void valueChanged(TreeSelectionEvent e) {
-                if (e.isAddedPath()) {
-                    fireViewAction(Action.HOST_VM_SELECTION_CHANGED);
-                }
-            }
-        });
-        registerContextActionListener(agentVmTree);
-        
-        JScrollPane treeScrollPane = new JScrollPane(agentVmTree);
-        
-        navigationPanel.add(treeScrollPane);
-
-        JPanel detailsPanel = createDetailsPanel();
-
-        navigationPanel.setMinimumSize(new Dimension(200,500));
-        detailsPanel.setMinimumSize(new Dimension(500, 500));
-
-        splitPane.add(navigationPanel);
-        splitPane.add(detailsPanel);
-
-        getContentPane().add(splitPane);
-    }
-
-    private void registerContextActionListener(JTree agentVmTree2) {
-        vmContextMenu = new JPopupMenu();
-        agentVmTree2.addMouseListener(new MouseAdapter() {
-            @Override
-            public void mousePressed(MouseEvent e) {
-                if (e.isPopupTrigger()) {
-                    Ref ref = getSelectedHostOrVm();
-                    if (ref instanceof VmRef) {
-                        fireViewAction(Action.SHOW_VM_CONTEXT_MENU, e);
-                    }
-                }
-            }
-        });
-    }
-
-    @Override
-    public void showVMContextActions(final List<VMContextAction> actions, final MouseEvent e) {
-        SwingUtilities.invokeLater(new Runnable() {
-
-            @Override
-            public void run() {
-                vmContextMenu.removeAll();
-
-                for (final VMContextAction action: actions) {
-                    JMenuItem contextAction = new JMenuItem();
-                    contextAction.setText(action.getName());
-                    contextAction.setToolTipText(action.getDescription());
-
-                    contextAction.addActionListener(new java.awt.event.ActionListener() {
-                        @Override
-                        public void actionPerformed(java.awt.event.ActionEvent e) {
-                            fireViewAction(Action.VM_CONTEXT_ACTION, action);
-                        }
-                    });
-                    vmContextMenu.add(contextAction);
-                }
-
-                vmContextMenu.show((Component)e.getSource(), e.getX(), e.getY());
-            }
-
-        });
-    }
-    
-    private JPanel createDetailsPanel() {
-        JPanel result = new JPanel(new BorderLayout());
-        result.add(contentArea, BorderLayout.CENTER);
-        return result;
-    }
-
-    @SuppressWarnings("restriction")
-    public class ShutdownClient extends WindowAdapter implements java.awt.event.ActionListener, sun.misc.SignalHandler {
-
-        @Override
-        public void windowClosing(WindowEvent e) {
-            shutdown();
-        }
-
-        @Override
-        public void actionPerformed(java.awt.event.ActionEvent e) {
-            shutdown();
-        }
-        
-        @Override
-        public void handle(Signal arg0) {
-            shutdown();
-        }
-
-        private void shutdown() {
-            dispose();
-            fireViewAction(Action.SHUTDOWN);
-        }
-
-    }
-
-    private static class AgentVmTreeCellRenderer extends DefaultTreeCellRenderer {
-        private static final long serialVersionUID = 4444642511815252481L;
-
-        @Override
-        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
-            
-            Object node = ((DefaultMutableTreeNode) value).getUserObject();
-            setToolTipText(createToolTipText(node));
-            
-            Component component = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
-            if (value instanceof DecoratedDefaultMutableTreeNode) {
-                DecoratedDefaultMutableTreeNode treeNode = (DecoratedDefaultMutableTreeNode) value;
-                setAnnotation(treeNode, node, component);
-            }
-
-            return component;
-        }
-        
-        // TODO: we can cache more, for example the full icon, not just the decoration
-        private Map<Decorator, ImageIcon> decoratorsCache = new HashMap<>();
-        private void setAnnotation(DecoratedDefaultMutableTreeNode treeNode, Object value, Component component) {
-
-            List<Decorator> decorators = treeNode.getDecorators();
-            for (Decorator dec : decorators) {
-                String newText = dec.getLabel(getText());
-                setText(newText);
-                setLabelFor(component);
-                
-                ImageIcon icon = decoratorsCache.get(dec);
-                if (icon == null) {
-                    //System.err.println("cache miss: " + dec);
-                    IconDescriptor iconDescriptor = dec.getIconDescriptor();
-                    if (iconDescriptor != null) {
-                        ByteBuffer data = iconDescriptor.getData();
-                        icon = new ImageIcon(data.array());
-                        decoratorsCache.put(dec, icon);
-                    }
-                }
-                
-                if (icon == null) {
-                    return;
-                }
-                
-                Icon currentIcon = getIcon();
-                switch (dec.getQuadrant()) {
-                case BOTTOM_LEFT:
-                    int y = currentIcon.getIconHeight() - icon.getIconHeight();
-                    paintCustomIcon(currentIcon, icon, y);
-                    break;
-                    
-                case TOP_LEFT:
-                    paintCustomIcon(currentIcon, icon, 0);
-                    break;
-                    
-                case MAIN:
-                default:
-                    setIcon(icon);
-                    break;
-                }
-            }
-        }
-        
-        private void paintCustomIcon(Icon currentIcon, ImageIcon icon, int y) {
-            BufferedImage image = new BufferedImage(currentIcon.getIconWidth(),
-                                                    currentIcon.getIconHeight(),
-                                                    BufferedImage.TYPE_INT_ARGB);
-            Graphics2D graphics = (Graphics2D) image.getGraphics();
-            
-            currentIcon.paintIcon(null, graphics, 0, 0);
-            graphics.drawImage(icon.getImage(), 0, y, null);
-            
-            setIcon(new ImageIcon(image));
-        }
-        
-        private String createToolTipText(Object value) {
-            if (value instanceof HostRef) {
-                HostRef hostRef = (HostRef) value;
-                String hostNameHtml = new HtmlTextBuilder().bold(hostRef.getHostName()).toPartialHtml();
-                String agentIdHtml = new HtmlTextBuilder().bold(hostRef.getAgentId()).toPartialHtml();
-                HtmlTextBuilder builder = new HtmlTextBuilder()
-                    .appendRaw(translator.localize(LocaleResources.TREE_HOST_TOOLTIP_HOST_NAME, hostNameHtml))
-                    .newLine()
-                    .appendRaw(translator.localize(LocaleResources.TREE_HOST_TOOLTIP_AGENT_ID, agentIdHtml));
-                return builder.toHtml();
-            } else if (value instanceof VmRef) {
-                VmRef vmRef = (VmRef) value;
-                String vmNameHtml= new HtmlTextBuilder().bold(vmRef.getName()).toPartialHtml();
-                String vmIdHtml = new HtmlTextBuilder().bold(vmRef.getIdString()).toPartialHtml();
-                HtmlTextBuilder builder = new HtmlTextBuilder()
-                    .appendRaw(translator.localize(LocaleResources.TREE_HOST_TOOLTIP_VM_NAME, vmNameHtml))
-                    .newLine()
-                    .appendRaw(translator.localize(LocaleResources.TREE_HOST_TOOLTIP_VM_ID, vmIdHtml));
-                return builder.toHtml();
-            } else {
-                return null;
-            }
-        }
-    }
-
-    @Override
-    public void addActionListener(ActionListener<Action> l) {
-        actionNotifier.addActionListener(l);
-    }
-
-    public void removeViewActionListener(ActionListener<Action> l) {
-        actionNotifier.removeActionListener(l);
-    }
-
-    private void fireViewAction(Action action) {
-        actionNotifier.fireAction(action);
-    }
-    
-    private void fireViewAction(Action action, Object payload) {
-        actionNotifier.fireAction(action, payload);
-    }
-    
-    @Override
-    public void updateTree(List<HostFilter> hostFilters, List<VmFilter> vmFilters,
-            List<HostDecorator> hostDecorators, List<VmDecorator> vmDecorators,
-            HostsVMsLoader hostsVMsLoader)
-    {
-        BackgroundTreeModelWorker worker =
-                new BackgroundTreeModelWorker(publishedTreeModel, publishedRoot,
-                                              hostFilters, vmFilters, hostDecorators, vmDecorators, hostsVMsLoader, agentVmTree);
-        worker.execute();
-    }
-
-    @SuppressWarnings("unused") // Used for debugging but not in production code.
-    private static void printTree(PrintStream out, TreeNode node, int depth) {
-        out.println(StringUtils.repeat("  ", depth) + node.toString());
-        @SuppressWarnings("unchecked")
-        List<TreeNode> children = Collections.list(node.children());
-        for (TreeNode child : children) {
-            printTree(out, child, depth + 1);
-        }
-    }
-
-    @Override
-    public void setWindowTitle(String title) {
-        setTitle(title);
-    }
-
-    @Override
-    public void showMainWindow() {
-        try {
-            new EdtHelper().callAndWait(new Runnable() {
-
-                @Override
-                public void run() {
-                    pack();
-                    setVisible(true);
-                }
-            });
-        } catch (InvocationTargetException e) {
-            throw new RuntimeException(e);
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-        }
-    }
-
-    @Override
-    public void hideMainWindow() {
-        setVisible(false);
-        dispose();
-    }
-
-    @Override
-    public void setStatusBarPrimaryStatus(final String primaryStatus) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                statusBar.setPrimaryStatus(primaryStatus);
-            }
-        });
-    }
-    
-    @Override
-    public void setSubView(final BasicView view) {
-        if (view instanceof SwingComponent) {
-            final SwingComponent swingComp = (SwingComponent)view;
-            SwingUtilities.invokeLater(new Runnable() {
-                @Override
-                public void run() {
-                    contentArea.removeAll();
-                    Component toAdd = swingComp.getUiComponent();
-                    contentArea.add(toAdd);
-                    contentArea.revalidate();
-                }
-            });
-        }
-    }
-
-    @Override
-    public void addMenu(MenuAction action) {
-        mainMenuHelper.addMenuAction(action);
-    }
-
-    @Override
-    public void removeMenu(MenuAction action) {
-        mainMenuHelper.removeMenuAction(action);
-    }
-
-    /**
-     * Returns null to indicate no Ref is selected
-     */
-    @Override
-    public Ref getSelectedHostOrVm() {
-        TreePath path = agentVmTree.getSelectionPath();
-        if (path == null || path.getPathCount() == 1) {
-            return null;
-        }
-        return (Ref) ((DefaultMutableTreeNode) path.getLastPathComponent()).getUserObject();
-    }
-
-    @Override
-    public String getHostVmTreeFilterText() {
-        return searchField.getSearchText();
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/MemorySpacePanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +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.ui;
-
-import javax.swing.GroupLayout;
-import javax.swing.GroupLayout.Alignment;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JProgressBar;
-import javax.swing.LayoutStyle.ComponentPlacement;
-
-public class MemorySpacePanel extends JPanel {
-
-    private final JProgressBar percentagePanel;
-    private final JLabel additionalDetailsIcon;
-    private final JLabel lblUsed;
-    private final JLabel lblAvailable;
-
-    public MemorySpacePanel(String regionName) {
-        JLabel lblRegionName = new JLabel(regionName);
-
-        percentagePanel = new JProgressBar(0, 100);
-
-        additionalDetailsIcon = new JLabel(IconResource.ARROW_RIGHT.getIcon());
-
-        lblUsed = new JLabel("${USED}");
-        lblAvailable = new JLabel("${AVAILABLE}");
-
-        GroupLayout groupLayout = new GroupLayout(this);
-        groupLayout.setHorizontalGroup(
-            groupLayout.createParallelGroup(Alignment.LEADING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addContainerGap()
-                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
-                        .addComponent(lblRegionName)
-                        .addGroup(groupLayout.createSequentialGroup()
-                            .addGap(12)
-                            .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
-                                .addComponent(percentagePanel, GroupLayout.DEFAULT_SIZE, 574, Short.MAX_VALUE)
-                                .addGroup(groupLayout.createSequentialGroup()
-                                    .addComponent(lblUsed)
-                                    .addPreferredGap(ComponentPlacement.RELATED, 441, Short.MAX_VALUE)
-                                    .addComponent(lblAvailable)))))
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addComponent(additionalDetailsIcon)
-                    .addContainerGap())
-        );
-        groupLayout.setVerticalGroup(
-            groupLayout.createParallelGroup(Alignment.LEADING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addContainerGap()
-                    .addComponent(lblRegionName)
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
-                        .addComponent(additionalDetailsIcon, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                        .addComponent(percentagePanel, GroupLayout.DEFAULT_SIZE, 44, Short.MAX_VALUE))
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
-                        .addComponent(lblUsed)
-                        .addComponent(lblAvailable))
-                    .addGap(5))
-        );
-        setLayout(groupLayout);
-    }
-
-
-    public void updateRegionData(int percentageUsed, String currentlyUsed, String currentlyAvailable, String allocatable) {
-        percentagePanel.setValue(percentageUsed);
-
-        lblUsed.setText(currentlyUsed);
-        lblAvailable.setText(currentlyAvailable);
-        additionalDetailsIcon.setToolTipText(allocatable);
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/MenuHelper.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,287 +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.ui;
-
-import java.awt.event.ActionEvent;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Arrays;
-import java.util.logging.Logger;
-
-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JMenu;
-import javax.swing.JMenuBar;
-import javax.swing.JMenuItem;
-import javax.swing.JPopupMenu;
-import javax.swing.JRadioButtonMenuItem;
-import javax.swing.MenuElement;
-
-import com.redhat.thermostat.client.osgi.service.MenuAction;
-import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.common.utils.StringUtils;
-import com.redhat.thermostat.swing.EdtHelper;
-
-public class MenuHelper {
-
-    private static final Logger logger = LoggingUtils.getLogger(MenuHelper.class);
-
-    private final JMenuBar menuBar;
-
-    public MenuHelper(JMenuBar menuBar) {
-        this.menuBar = menuBar;
-    }
-
-    /**
-     * Add a menu item as specified though the {@link MenuAction} argument.
-     */
-    public void addMenuAction(final MenuAction action) {
-        try {
-            new EdtHelper().callAndWait(new Runnable() {
-                @Override
-                public void run() {
-                    String[] path = action.getPath();
-                    Menu parent = findMenuParent(menuBar, path, true);
-                    JMenuItem menu = null;
-                    switch (action.getType()) {
-                    case RADIO:
-                        menu = new JRadioButtonMenuItem();
-                        break;
-                    case CHECK:
-                        menu = new JCheckBoxMenuItem();
-                        break;
-
-                    case STANDARD:
-                    default:
-                        menu = new JMenuItem();
-                        break;
-                    }
-
-                    menu.setText(action.getName());
-                    menu.addActionListener(new java.awt.event.ActionListener() {
-                        @Override
-                        public void actionPerformed(ActionEvent e) {
-                            action.execute();
-                        }
-                    });
-                    parent.add(new Menu(menu));
-
-                    menuBar.revalidate();
-                }
-            });
-        } catch (InvocationTargetException ite) {
-            Throwable cause = ite.getCause();
-            if (cause instanceof IllegalArgumentException) {
-                throw (IllegalArgumentException) cause;
-            }
-            throw new RuntimeException(cause);
-        } catch (InterruptedException ie) {
-            Thread.currentThread().interrupt();
-            throw new RuntimeException(ie);
-        }
-
-    }
-
-    /**
-     * Remove a existing menu item as specified though the {@link MenuAction}
-     * argument.
-     *
-     * @throws IllegalArgumentException if the path specified in
-     * {@link MenuAction#getPath()} can not be found
-     */
-    public void removeMenuAction(final MenuAction action) {
-        try {
-            new EdtHelper().callAndWait(new Runnable() {
-                @Override
-                public void run() {
-                    String[] path = action.getPath();
-                    Menu parent = findMenuParent(menuBar, path, false);
-                    parent.remove(path[path.length - 1]);
-                    menuBar.revalidate();
-                }
-            });
-        } catch (InterruptedException ie) {
-            Thread.currentThread().interrupt();
-            throw new RuntimeException(ie);
-        } catch (InvocationTargetException roe) {
-            Throwable cause = roe.getCause();
-            if (cause instanceof IllegalArgumentException) {
-                throw (IllegalArgumentException) cause;
-            }
-            throw new RuntimeException(cause);
-        }
-
-    }
-
-    private static Menu findMenuParent(JMenuBar menuBar, String[] path, boolean createIfNotFound) {
-        Menu parent = null;
-        int mainMenuCount = menuBar.getMenuCount();
-        for (int i = 0; i < mainMenuCount; i++) {
-            JMenu menu = menuBar.getMenu(i);
-            if (menu.getText().equals(path[0])) {
-                parent = new Menu(menuBar.getMenu(i));
-                break;
-            }
-        }
-        if (parent == null) {
-            if (createIfNotFound) {
-                JMenu delegate = new JMenu(path[0]);
-                parent = new Menu(delegate);
-                menuBar.add(delegate);
-            } else {
-                throw new IllegalArgumentException("top-level " + path[0] + " not found (using path" + Arrays.toString(path) + ")");
-            }
-        }
-
-        for (int i = 1; i < path.length - 1; i++) {
-            Menu[] children = parent.children();
-            boolean found = false;
-            for (int j = 0; j < children.length; j++) {
-                Menu menu = children[j];
-                if (menu.getText().equals(path[i])) {
-                    parent = menu;
-                    found = true;
-                }
-            }
-            if (!found) {
-                if (createIfNotFound) {
-                    Menu newMenu = new Menu(new JMenu(path[i]));
-                    parent.add(newMenu);
-                    parent = newMenu;
-                } else {
-                    throw new IllegalArgumentException("path not found");
-                }
-            }
-        }
-
-        return parent;
-    }
-
-    private static String getText(MenuElement element) {
-        if (element instanceof JMenuItem) {
-            return ((JMenuItem) element).getText();
-        }
-        return "";
-    }
-
-    @SuppressWarnings("unused") // this method is for debugging only
-    private static void printMenu(MenuElement parent, int nestingLevel) {
-        System.out.println(StringUtils.repeat(" ", nestingLevel * 2) + getText(parent) + " [" + parent.getClass() + "]");
-        for (MenuElement element : parent.getSubElements()) {
-            printMenu(element, nestingLevel + 1);
-        }
-    }
-
-    /**
-     * The swing menu hierarchy makes uniform operations very difficult. This
-     * is a hack around that.
-     */
-    private static final class Menu {
-        private Object swingDelegate;
-
-        public Menu() { /* no op */}
-
-        public Menu(JMenuItem actual) {
-            this.swingDelegate = actual;
-        }
-
-        public String getText() {
-            if (swingDelegate instanceof JMenuItem) {
-                return ((JMenuItem) swingDelegate).getText();
-            }
-            return null;
-        }
-
-        public Menu[] children() {
-            if (swingDelegate instanceof MenuElement) {
-                MenuElement[] actualChildren = ((MenuElement) swingDelegate).getSubElements();
-                if (actualChildren.length == 1 && actualChildren[0] instanceof JPopupMenu) {
-                    actualChildren = actualChildren[0].getSubElements();
-                }
-
-                Menu[] children = new Menu[actualChildren.length];
-                for (int i = 0; i < children.length; i++) {
-                    children[i] = new Menu((JMenuItem) actualChildren[i]);
-                }
-                return children;
-            }
-            return new Menu[0];
-        }
-
-        public void add(Menu menu) {
-            if (swingDelegate instanceof JPopupMenu) {
-                ((JPopupMenu) swingDelegate).add((JMenuItem) menu.swingDelegate);
-            } else if (swingDelegate instanceof JMenu) {
-                ((JMenu) swingDelegate).add((JMenuItem) menu.swingDelegate);
-            } else {
-                logger.warning("Unable to add menu. Menu is of unrecognized type: " + menu.swingDelegate);
-            }
-        }
-
-        public void remove(String string) {
-            JPopupMenu removeParent = null;
-
-            if (swingDelegate instanceof JMenu) {
-                JMenu parent = (JMenu) swingDelegate;
-                MenuElement[] actualChildren = parent.getSubElements();
-                if (actualChildren.length == 1 && actualChildren[0] instanceof JPopupMenu) {
-                    removeParent = (JPopupMenu) actualChildren[0];
-                }
-            }
-
-            if (removeParent == null) {
-                if (swingDelegate instanceof JPopupMenu) {
-                    removeParent = (JPopupMenu) swingDelegate;
-                } else {
-                    logger.warning("BUG: problem while removing menu. delegate is not a JPopupMenu, cant remove");
-                    return;
-                }
-            }
-
-            JPopupMenu parent = removeParent;
-            for (MenuElement element : parent.getSubElements()) {
-                if (((JMenuItem) element).getText().equals(string)) {
-                    parent.remove((JMenuItem) element);
-                }
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "Menu [" + swingDelegate.toString() + "]";
-        }
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/Palette.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.ui;
+
+import java.awt.Color;
+
+public enum Palette {
+
+    THERMOSTAT_BLU(new Color(74, 93, 117)),
+    THERMOSTAT_RED(new Color(226, 46, 42)),
+    
+    RED(new Color(192, 0, 0)),
+    PALE_RED(new Color(192, 80, 77)),
+    
+    SKY_BLUE(new Color(79, 129, 189)),
+    AZUREUS(new Color(0, 176, 190)),
+    EGYPTIAN_BLUE(new Color(74, 144, 217)),
+    DIRTY_CYAN(new Color(75, 172, 198)),
+    PRUSSIAN_BLUE(new Color(0, 49, 83)),
+    
+    GREEN(new Color(146, 208, 80)),
+    TUNDRA_GREEN(new Color(155, 187, 89)),
+
+    POMP_AND_POWER_VIOLET(new Color(128, 100, 162)),
+    VIOLET(new Color(112, 48, 160)),
+
+    EARL_GRAY(new Color(128, 128, 128)),
+    
+    PALE_GRAY(new Color(235, 235, 235)),
+    LIGHT_GRAY(new Color(242, 242, 242)),
+    GRAY(new Color(216, 216, 216)),
+    DARK_GRAY(new Color(168, 172, 168)),
+
+    GRANITA_ORANGE(new Color(247,150,70)),
+    
+    BLACK(Color.BLACK),
+    WHITE(Color.WHITE),
+
+    /* END */ ;
+    
+    private Color color;
+    Palette(Color color) {
+        this.color = color;
+    }
+    
+    public Color getColor() {
+        return color;
+    }
+}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/RecentTimeSeriesChartPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,219 +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.ui;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.concurrent.TimeUnit;
-
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JTextField;
-import javax.swing.SwingUtilities;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.Document;
-import javax.swing.text.JTextComponent;
-
-import org.jfree.chart.ChartPanel;
-
-import com.redhat.thermostat.client.locale.LocaleResources;
-import com.redhat.thermostat.common.locale.Translate;
-
-public class RecentTimeSeriesChartPanel extends JPanel {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private static final long serialVersionUID = -1733906800911900456L;
-    private static final int MINIMUM_DRAW_SIZE = 100;
-
-    private final RecentTimeSeriesChartController controller;
-
-    private JPanel labelContainer;
-    private JTextComponent label;
-
-    public RecentTimeSeriesChartPanel(RecentTimeSeriesChartController controller) {
-        this.controller = controller;
-
-        this.setLayout(new BorderLayout());
-
-        final ChartPanel cp = controller.getChartPanel();
-
-        cp.setDisplayToolTips(false);
-        cp.setDoubleBuffered(true);
-        cp.setMouseZoomable(false);
-        cp.setPopupMenu(null);
-
-        /*
-         * 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.
-         */
-        cp.setMinimumDrawHeight(MINIMUM_DRAW_SIZE);
-        cp.setMaximumDrawHeight(Integer.MAX_VALUE);
-        cp.setMinimumDrawWidth(MINIMUM_DRAW_SIZE);
-        cp.setMaximumDrawWidth(Integer.MAX_VALUE);
-
-        add(getControlsAndAdditionalDisplay(), BorderLayout.SOUTH);
-
-        add(cp, BorderLayout.CENTER);
-    }
-
-    private Component getControlsAndAdditionalDisplay() {
-        JPanel container = new JPanel();
-        container.setOpaque(false);
-
-        container.setLayout(new BorderLayout());
-
-        container.add(getChartControls(), BorderLayout.LINE_START);
-        container.add(getAdditionalDataDisplay(), BorderLayout.LINE_END);
-
-        return container;
-    }
-
-    private Component getChartControls() {
-        JPanel container = new JPanel();
-        container.setOpaque(false);
-
-        final JTextField durationSelector = new JTextField(5);
-        final JComboBox<TimeUnit> unitSelector = new JComboBox<>();
-        unitSelector.setModel(new DefaultComboBoxModel<>(controller.getTimeUnits()));
-
-        int defaultValue = controller.getTimeValue();
-        TimeUnit defaultUnit = controller.getTimeUnit();
-
-        TimeUnitChangeListener timeUnitChangeListener = new TimeUnitChangeListener(controller, defaultValue, defaultUnit);
-
-        durationSelector.getDocument().addDocumentListener(timeUnitChangeListener);
-        unitSelector.addActionListener(timeUnitChangeListener);
-
-        durationSelector.setText(String.valueOf(defaultValue));
-        unitSelector.setSelectedItem(defaultUnit);
-
-        container.add(new JLabel(translator.localize(LocaleResources.CHART_DURATION_SELECTOR_LABEL)));
-        container.add(durationSelector);
-        container.add(unitSelector);
-
-        return container;
-    }
-
-    private Component getAdditionalDataDisplay() {
-        JPanel panel = new JPanel(new GridBagLayout());
-        panel.setOpaque(false);
-        labelContainer = new JPanel();
-        labelContainer.setOpaque(false);
-        GridBagConstraints constraints = new GridBagConstraints();
-        constraints.fill = GridBagConstraints.BOTH;
-        constraints.anchor = GridBagConstraints.CENTER;
-        panel.add(labelContainer, constraints);
-        return panel;
-    }
-
-    public void setDataInformationLabel(final String text) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                if (label == null) {
-                    label = new ValueField(text);
-                    labelContainer.add(label);
-                }
-
-                label.setText(text);
-            }
-        });
-    }
-
-    private static class TimeUnitChangeListener implements DocumentListener, ActionListener {
-
-        private final RecentTimeSeriesChartController controller;
-        private int value;
-        private TimeUnit unit;
-
-        public TimeUnitChangeListener(RecentTimeSeriesChartController controller, int defaultValue, TimeUnit defaultUnit) {
-            this.controller = controller;
-            this.value = defaultValue;
-            this.unit = defaultUnit;
-        }
-
-        @Override
-        public void removeUpdate(DocumentEvent event) {
-            changed(event.getDocument());
-        }
-
-        @Override
-        public void insertUpdate(DocumentEvent event) {
-            changed(event.getDocument());
-        }
-
-        @Override
-        public void changedUpdate(DocumentEvent event) {
-            changed(event.getDocument());
-        }
-
-        private void changed(Document doc) {
-            try {
-                this.value = Integer.valueOf(doc.getText(0, doc.getLength()));
-            } catch (NumberFormatException nfe) {
-                // ignore
-            } catch (BadLocationException ble) {
-                // ignore
-            }
-            updateChartParameters();
-        }
-
-        private void updateChartParameters() {
-            controller.setTime(value, unit);
-        }
-
-        @Override
-        public void actionPerformed(ActionEvent e) {
-            @SuppressWarnings("unchecked") // We are a TimeUnitChangeListener, specifically.
-            JComboBox<TimeUnit> comboBox = (JComboBox<TimeUnit>) e.getSource();
-            TimeUnit time = (TimeUnit) comboBox.getSelectedItem();
-            this.unit = time;
-            updateChartParameters();
-        }
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/SearchFieldSwingView.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,224 +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.ui;
-
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
-import java.lang.reflect.InvocationTargetException;
-import java.util.concurrent.Callable;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-
-import javax.swing.BorderFactory;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JTextField;
-import javax.swing.SwingUtilities;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.Document;
-
-import com.redhat.thermostat.client.locale.LocaleResources;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.ActionNotifier;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.swing.EdtHelper;
-
-public class SearchFieldSwingView extends JPanel implements SearchFieldView {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private final ActionNotifier<SearchAction> notifier = new ActionNotifier<>(this);
-    private final JTextField searchField = new JTextField();
-
-    private final AtomicReference<String> searchText = new AtomicReference<String>("");
-    private final AtomicReference<String> label = new AtomicReference<>(translator.localize(LocaleResources.SEARCH_HINT));
-    private final AtomicBoolean labelDisplayed = new AtomicBoolean(true);
-
-    public SearchFieldSwingView() {
-        super(new BorderLayout());
-
-        // TODO move this icon inside the search field
-        JLabel searchIcon = new JLabel(IconResource.SEARCH.getIcon());
-        searchIcon.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
-
-        searchField.setText(label.get());
-        searchField.setName(VIEW_NAME);
-        /* the insets are so we can place the actual icon inside the searchField */
-        searchField.setMargin(new Insets(0, 0, 0, 30));
-
-        searchField.getDocument().addDocumentListener(new DocumentListener() {
-
-            private String previousText = searchText.get();
-
-            @Override
-            public void removeUpdate(DocumentEvent event) {
-                changed(event.getDocument());
-            }
-
-            @Override
-            public void insertUpdate(DocumentEvent event) {
-                changed(event.getDocument());
-            }
-
-            @Override
-            public void changedUpdate(DocumentEvent event) {
-                changed(event.getDocument());
-            }
-
-            private void changed(Document doc) {
-                if (!labelDisplayed.get()) {
-                    String filter = null;
-                    try {
-                        filter = doc.getText(0, doc.getLength());
-                    } catch (BadLocationException ble) {
-                        // ignore
-                    }
-
-                    searchText.set(filter);
-                    if (!(filter.equals(previousText))) {
-                        previousText = filter;
-                        fireViewAction(SearchAction.TEXT_CHANGED);
-                    }
-                }
-            }
-        });
-
-        final Color originalForegroundColor = searchField.getForeground();
-        searchField.addFocusListener(new FocusListener() {
-
-            @Override
-            public void focusLost(FocusEvent e) {
-                if (searchText.get().equals("")) {
-                    labelDisplayed.set(true);
-                    searchField.setForeground(Color.GRAY);
-                    searchField.setText(label.get());
-                }
-            }
-
-            @Override
-            public void focusGained(FocusEvent e) {
-                if (labelDisplayed.get()) {
-                    labelDisplayed.set(false);
-                    searchField.setForeground(originalForegroundColor);
-                    searchField.setText("");
-                }
-
-            }
-        });
-
-        final java.awt.event.ActionListener searchActionListener = new java.awt.event.ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                fireViewAction(SearchAction.PERFORM_SEARCH);
-            }
-        };
-
-        searchField.addActionListener(searchActionListener);
-
-        add(searchField);
-        add(searchIcon, BorderLayout.LINE_END);
-
-    }
-
-    @Override
-    public String getSearchText() {
-        try {
-            return new EdtHelper().callAndWait(new Callable<String>() {
-                @Override
-                public String call() throws Exception {
-                    return searchText.get();
-                }
-            });
-        } catch (InvocationTargetException | InterruptedException e) {
-            return null;
-        }
-    }
-
-    @Override
-    public void setSearchText(final String text) {
-        searchText.set(text);
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                searchField.setText(text);
-            }
-        });
-    }
-
-    @Override
-    public void setLabel(String label) {
-        this.label.set(label);
-        if (labelDisplayed.get()) {
-            SwingUtilities.invokeLater(new Runnable() {
-                @Override
-                public void run() {
-                    searchField.setText(SearchFieldSwingView.this.label.get());
-                }
-            });
-        }
-    }
-
-    @Override
-    public void setTooltip(final String tooltip) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                searchField.setToolTipText(tooltip);
-            }
-        });
-    }
-
-    @Override
-    public void addActionListener(ActionListener<SearchAction> listener) {
-        notifier.addActionListener(listener);
-    }
-
-    @Override
-    public void removeActionListener(ActionListener<SearchAction> listener) {
-        notifier.removeActionListener(listener);
-    }
-
-    private void fireViewAction(SearchAction action) {
-        notifier.fireAction(action);
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/SearchFieldView.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +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.ui;
-
-import com.redhat.thermostat.client.core.views.View;
-import com.redhat.thermostat.common.ActionListener;
-
-public interface SearchFieldView extends View {
-
-    /** For use by tests only */
-    public static final String VIEW_NAME = "searchField";
-
-    public enum SearchAction {
-        TEXT_CHANGED,
-        PERFORM_SEARCH,
-    }
-
-    public String getSearchText();
-
-    public void setSearchText(String text);
-
-    void setLabel(String label);
-
-    void setTooltip(String tooltip);
-
-    public void addActionListener(ActionListener<SearchAction> listener);
-    public void removeActionListener(ActionListener<SearchAction> listener);
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/SectionHeader.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.ui;
-
-import javax.swing.JLabel;
-import javax.swing.SwingConstants;
-
-public class SectionHeader extends JLabel {
-
-    public SectionHeader(String text) {
-        super(HtmlTextBuilder.boldHtml(text));
-        setHorizontalAlignment(SwingConstants.LEADING);
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/SimpleTable.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,289 +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.ui;
-
-import java.awt.Component;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import javax.swing.Box;
-import javax.swing.JComponent;
-import javax.swing.JEditorPane;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JTextArea;
-import javax.swing.JTextField;
-import javax.swing.SwingUtilities;
-
-import com.redhat.thermostat.client.internal.ChangeableText;
-
-public class SimpleTable implements ChangeableText.TextListener {
-
-    Map<ChangeableText, Set<JComponent>> updateMap = new HashMap<ChangeableText, Set<JComponent>>();
-
-    public static class Section {
-        private final String sectionName;
-        private final List<TableEntry> tableEntries = new ArrayList<TableEntry>();
-
-        public Section(String name) {
-            this.sectionName = name;
-        }
-
-        public String getText() {
-            return sectionName;
-        }
-
-        public void add(TableEntry entry) {
-            tableEntries.add(entry);
-        }
-
-        public void add(Key key, List<Value> values) {
-            tableEntries.add(new TableEntry(key, values));
-        }
-
-        public void add(Key key, Value value) {
-            tableEntries.add(new TableEntry(key, value));
-        }
-
-        public TableEntry[] getEntries() {
-            return tableEntries.toArray(new TableEntry[0]);
-        }
-    }
-
-    public static class TableEntry {
-        private final Key key;
-        private final List<Value> values;
-
-        public TableEntry(String key, ChangeableText value) {
-            this(new Key(key), new Value(value));
-        }
-
-        public TableEntry(Key key, Value value) {
-            this.key = key;
-            this.values = new ArrayList<Value>();
-            this.values.add(value);
-        }
-
-        public TableEntry(Key key, List<Value> values) {
-            this.key = key;
-            this.values = new ArrayList<Value>(values);
-        }
-
-        public Key getKey() {
-            return key;
-        }
-
-        public Value[] getValues() {
-            return values.toArray(new Value[0]);
-        }
-    }
-
-    public static class Key {
-        private final String text;
-
-        public Key(String text) {
-            this.text = text;
-        }
-
-        public String getText() {
-            return text;
-        }
-    }
-
-    public static class Value {
-        private final ChangeableText text;
-        private final Component actualComponent;
-
-        public Value(String text) {
-            this(new ChangeableText(text));
-        }
-
-        public Value(ChangeableText text) {
-            this.text = text;
-            this.actualComponent = null;
-        }
-
-        public Value(Component component) {
-            this.actualComponent = component;
-            this.text = null;
-        }
-
-        public Component getComponent() {
-            return actualComponent;
-        }
-
-        public ChangeableText getChangeableText() {
-            return text;
-        }
-    }
-
-    public JPanel createTable(List<Section> sections) {
-        final int SECTION_TOP_GAP = 10;
-        final int ROW_VERTICAL_GAP = 0;
-        final int ROW_HORIZONTAL_GAP = 10;
-
-        Insets sectionHeaderInsets = new Insets(SECTION_TOP_GAP, 0, 0, 0);
-        Insets rowInsets = new Insets(ROW_VERTICAL_GAP, ROW_HORIZONTAL_GAP, ROW_VERTICAL_GAP, ROW_HORIZONTAL_GAP);
-
-        JPanel container = new JPanel();
-        container.setLayout(new GridBagLayout());
-
-        GridBagConstraints keyConstraints = new GridBagConstraints();
-        GridBagConstraints valueConstraints = new GridBagConstraints();
-        GridBagConstraints sectionHeaderConstraints = new GridBagConstraints();
-
-        keyConstraints.insets = valueConstraints.insets = rowInsets;
-        keyConstraints.gridy = valueConstraints.gridy = 0;
-        keyConstraints.gridx = 0;
-        keyConstraints.anchor = GridBagConstraints.FIRST_LINE_END;
-        valueConstraints.gridx = 1;
-        keyConstraints.fill = valueConstraints.fill = GridBagConstraints.HORIZONTAL;
-
-        sectionHeaderConstraints.gridx = 0;
-        sectionHeaderConstraints.gridwidth = GridBagConstraints.REMAINDER;
-        sectionHeaderConstraints.fill = GridBagConstraints.HORIZONTAL;
-        sectionHeaderConstraints.insets = sectionHeaderInsets;
-
-        for (Section section : sections) {
-            sectionHeaderConstraints.gridy = keyConstraints.gridy = ++valueConstraints.gridy;
-            container.add(Components.header(section.getText()), sectionHeaderConstraints);
-            for (TableEntry tableEntry : section.getEntries()) {
-                keyConstraints.gridy = ++valueConstraints.gridy;
-                container.add(Components.label(tableEntry.getKey().getText()), keyConstraints);
-
-                for (Value value : tableEntry.getValues()) {
-                    if (value.getComponent() == null) {
-                        ChangeableText text = value.getChangeableText();
-                        JComponent valueLabel = new ValueField(text.getText());
-                        if (updateMap.containsKey(text)) {
-                            updateMap.get(text).add(valueLabel);
-                        } else {
-                            Set<JComponent> set = new HashSet<JComponent>();
-                            set.add(valueLabel);
-                            updateMap.put(text, set);
-                        }
-                        container.add(valueLabel, valueConstraints);
-                    } else {
-                        container.add(value.getComponent(), valueConstraints);
-                    }
-                    keyConstraints.gridy = ++valueConstraints.gridy;
-                }
-            }
-        }
-
-        GridBagConstraints glueConstraints = new GridBagConstraints();
-        glueConstraints.gridy = keyConstraints.gridy + 1;
-        glueConstraints.gridx = 0;
-        glueConstraints.weightx = 1;
-        glueConstraints.weighty = 1;
-        glueConstraints.fill = GridBagConstraints.BOTH;
-        glueConstraints.gridheight = GridBagConstraints.REMAINDER;
-        glueConstraints.gridwidth = GridBagConstraints.REMAINDER;
-        Component filler = Box.createGlue();
-        container.add(filler, glueConstraints);
-
-        container.addHierarchyListener(new ComponentVisibleListener() {
-            @Override
-            public void componentShown(Component c) {
-                updateAllValues();
-                addAllListeners();
-            }
-
-            @Override
-            public void componentHidden(Component c) {
-                removeAllListeners();
-            }
-        });
-
-        return container;
-    }
-
-
-    private void updateAllValues() {
-        for (Entry<ChangeableText, Set<JComponent>> entry: updateMap.entrySet()) {
-            for (JComponent label: entry.getValue()) {
-                setText(label, entry.getKey().getText());
-            }
-        }
-    }
-
-    private static void setText(JComponent target, String text) {
-        if (target instanceof JLabel) {
-            ((JLabel)target).setText(text);
-        } else if (target instanceof JTextField) {
-            ((JTextField)target).setText(text);
-        } else if (target instanceof JTextArea) {
-            ((JTextArea)target).setText(text);
-        } else if (target instanceof JEditorPane) {
-            ((JEditorPane)target).setText(text);
-        }
-    }
-
-    @Override
-    public void textChanged(final ChangeableText text) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                String newValue = text.getText();
-                for (JComponent label: updateMap.get(text)) {
-                    setText(label, newValue);
-                }
-            }
-        });
-    }
-
-    public void addAllListeners() {
-        for (ChangeableText text : updateMap.keySet()) {
-            text.addListener(this);
-        }
-    }
-
-    public void removeAllListeners() {
-        for (ChangeableText text : updateMap.keySet()) {
-            text.removeListener(this);
-        }
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/SummaryPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,216 +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.ui;
-
-import java.awt.Component;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.AbstractListModel;
-import javax.swing.GroupLayout;
-import javax.swing.GroupLayout.Alignment;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.LayoutStyle.ComponentPlacement;
-import javax.swing.ListModel;
-import javax.swing.SwingUtilities;
-import javax.swing.text.JTextComponent;
-
-import com.redhat.thermostat.client.core.views.SummaryView;
-import com.redhat.thermostat.client.locale.LocaleResources;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.locale.Translate;
-
-public class SummaryPanel extends SummaryView implements SwingComponent {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private JPanel visiblePanel;
-    
-    private final JTextComponent totalMonitoredHosts;
-    private final JTextComponent totalMonitoredVms;
-
-    private final List<String> issuesList;
-
-    public SummaryPanel() {
-        super();
-        visiblePanel = new JPanel();
-        JLabel lblHomepanel = Components.header(translator.localize(LocaleResources.HOME_PANEL_SECTION_SUMMARY));
-
-        JLabel lblTotalHosts = new JLabel(translator.localize(LocaleResources.HOME_PANEL_TOTAL_MACHINES));
-
-        totalMonitoredHosts = new ValueField("${TOTAL_MONITORED_HOSTS}");
-
-        JLabel lblTotal = new JLabel(translator.localize(LocaleResources.HOME_PANEL_TOTAL_JVMS));
-
-        totalMonitoredVms = new ValueField("${TOTAL_MONITORED_VMS}");
-
-        JLabel lblIssues = Components.header(translator.localize(LocaleResources.HOME_PANEL_SECTION_ISSUES));
-
-        JScrollPane scrollPane = new JScrollPane();
-
-        GroupLayout groupLayout = new GroupLayout(visiblePanel);
-        groupLayout.setHorizontalGroup(
-            groupLayout.createParallelGroup(Alignment.TRAILING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
-                        .addGroup(groupLayout.createSequentialGroup()
-                            .addContainerGap()
-                            .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
-                                .addComponent(lblHomepanel)
-                                .addGroup(groupLayout.createSequentialGroup()
-                                    .addGap(12)
-                                    .addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
-                                        .addComponent(lblTotal)
-                                        .addComponent(lblTotalHosts))
-                                    .addGap(18)
-                                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
-                                        .addComponent(totalMonitoredVms, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                                        .addComponent(totalMonitoredHosts, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
-                                .addComponent(lblIssues)))
-                        .addGroup(groupLayout.createSequentialGroup()
-                            .addGap(24)
-                            .addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
-                    .addContainerGap())
-        );
-        groupLayout.setVerticalGroup(
-            groupLayout.createParallelGroup(Alignment.LEADING)
-                .addGroup(groupLayout.createSequentialGroup()
-                    .addContainerGap()
-                    .addComponent(lblHomepanel)
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
-                        .addComponent(lblTotalHosts)
-                        .addComponent(totalMonitoredHosts, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE))
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
-                        .addComponent(lblTotal)
-                        .addComponent(totalMonitoredVms, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
-                    .addGap(18)
-                    .addComponent(lblIssues)
-                    .addPreferredGap(ComponentPlacement.RELATED)
-                    .addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
-                    .addContainerGap())
-        );
-
-        issuesList = new ArrayList<>();
-        ListModel<Object> issuesListModel = new IssuesListModel(issuesList);
-        JList<Object> issuesList = new JList<>();
-        issuesList.setModel(issuesListModel);
-        scrollPane.setViewportView(issuesList);
-        visiblePanel.setLayout(groupLayout);
-
-        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
-            @Override
-            public void componentShown(Component component) {
-                notifier.fireAction(Action.VISIBLE);
-            }
-
-            @Override
-            public void componentHidden(Component component) {
-                notifier.fireAction(Action.HIDDEN);
-            }
-        });
-    }
-
-    @Override
-    public void addActionListener(ActionListener<Action> listener) {
-        notifier.addActionListener(listener);
-    }
-
-    @Override
-    public void removeActionListener(ActionListener<Action> listener) {
-        notifier.removeActionListener(listener);
-    }
-
-    @Override
-    public void setTotalHosts(final String count) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                totalMonitoredHosts.setText(count);
-            }
-        });
-    }
-
-    @Override
-    public void setTotalVms(final String count) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                totalMonitoredVms.setText(count);
-            }
-        });
-    }
-
-    @Override
-    public Component getUiComponent() {
-        return visiblePanel;
-    }
-
-    private static class IssuesListModel extends AbstractListModel<Object> {
-
-        private static final long serialVersionUID = 7131506292620902850L;
-
-        private List<? extends Object> delegate;
-
-        private String emptyElement = translator.localize(LocaleResources.HOME_PANEL_NO_ISSUES);
-
-        public IssuesListModel(List<? extends Object> actualList) {
-            this.delegate = actualList;
-            // TODO observe the delegate for changes
-        }
-
-        @Override
-        public int getSize() {
-            if (delegate.isEmpty()) {
-                return 1;
-            }
-            return delegate.size();
-        }
-
-        @Override
-        public Object getElementAt(int index) {
-            if (delegate.isEmpty()) {
-                return emptyElement;
-            }
-            return delegate.get(index);
-        }
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/SwingComponent.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-package com.redhat.thermostat.client.ui;
-
-import java.awt.Component;
-
-import com.redhat.thermostat.client.core.views.UIComponent;
-
-public interface SwingComponent extends UIComponent {
-
-    Component getUiComponent();
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/UIResources.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +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.ui;
-
-import java.awt.Color;
-import java.awt.Font;
-
-import javax.swing.UIManager;
-import javax.swing.plaf.ColorUIResource;
-
-public class UIResources {
-
-    private static final UIResources resource = new UIResources();
-    
-    private static final ColorUIResource hyperLinkColor;
-    private static final ColorUIResource hyperLinkActiveColor;
-
-    private static final ColorUIResource selectionColor;
-    
-    private static final Font standard;
-    
-    static {
-        Color color = UIManager.getColor("Button.darkShadow");
-        if (color == null) {
-            color = Color.BLUE;
-        }
-        hyperLinkColor = new ColorUIResource(color);
-
-        color = UIManager.getColor("Button.focus");
-        if (color == null) {
-            color = Color.BLUE;
-        }
-        hyperLinkActiveColor = new ColorUIResource(color);
-        selectionColor = hyperLinkActiveColor;
-        
-        Font font = UIManager.getFont("Label.font");
-        if (font == null) {
-            font = Font.decode(Font.DIALOG);
-        }
-        standard = font;
-    }
-    
-    private static final Font header = standard.deriveFont(Font.BOLD);
-    
-    // TODO: check when size is too small
-    private static final Font footer = standard.deriveFont(Font.PLAIN, standard.getSize() - 2);
-    
-    private UIResources() { /* nothing to do */ }
-    
-    // colors
-
-    public static UIResources getInstance() {
-        return resource;
-    }
-    
-    public ColorUIResource hyperlinkColor() {
-        return hyperLinkColor;
-    }
-    
-    public ColorUIResource hyperlinkActiveColor() {
-        return hyperLinkActiveColor;
-    }
-    
-    public ColorUIResource getSelectionColor() {
-        return selectionColor;
-    }
-    
-    // font resources
-    
-    public Font footerFont() {
-        return footer;
-    }
-    
-    public Font headerFont() {
-        return header;
-    }
-    
-    public Font standardFont() {
-        return standard;
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/ValueField.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +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.ui;
-
-import javax.swing.JEditorPane;
-import javax.swing.UIManager;
-
-/**
- * A custom swing component meant for showing values. Use it like you would use
- * any other JTextComponent.
- */
-public class ValueField extends JEditorPane {
-
-    public ValueField(String text) {
-        setText(text);
-        setBorder(null);
-        setOpaque(false);
-        setBackground(UIManager.getColor("Label.background"));
-        setForeground(UIManager.getColor("Label.foreground"));
-        setFont(UIManager.getFont("Label.font"));
-        setEditable(false);
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/VmCpuController.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/VmCpuController.java	Fri Oct 26 15:32:56 2012 +0200
@@ -55,7 +55,7 @@
 import com.redhat.thermostat.common.model.DiscreteTimeData;
 import com.redhat.thermostat.common.model.VmCpuStat;
 
-class VmCpuController {
+public class VmCpuController {
 
     private final VmRef ref;
     private final VmCpuStatDAO dao;
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/VmCpuPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,148 +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.ui;
-
-import java.awt.Component;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.JPanel;
-import javax.swing.SwingUtilities;
-
-import org.jfree.chart.ChartFactory;
-import org.jfree.chart.JFreeChart;
-import org.jfree.data.time.FixedMillisecond;
-import org.jfree.data.time.RegularTimePeriod;
-import org.jfree.data.time.TimeSeries;
-import org.jfree.data.time.TimeSeriesCollection;
-
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.core.views.VmCpuView;
-import com.redhat.thermostat.client.locale.LocaleResources;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.model.DiscreteTimeData;
-import com.redhat.thermostat.swing.HeaderPanel;
-
-public class VmCpuPanel extends VmCpuView implements SwingComponent {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private HeaderPanel visiblePanel;
-    
-    private final TimeSeriesCollection data = new TimeSeriesCollection();
-    private final TimeSeries cpuTimeSeries = new TimeSeries("cpu-stats");
-
-    public VmCpuPanel() {
-        super();
-        data.addSeries(cpuTimeSeries);
-
-        initializePanel();
-
-        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
-            @Override
-            public void componentShown(Component component) {
-                notifier.fireAction(Action.VISIBLE);
-            }
-
-            @Override
-            public void componentHidden(Component component) {
-                notifier.fireAction(Action.HIDDEN);
-            }
-        });
-    }
-
-    @Override
-    public void addActionListener(ActionListener<Action> listener) {
-        notifier.addActionListener(listener);
-    }
-
-    @Override
-    public void removeActionListener(ActionListener<Action> listener) {
-        notifier.removeActionListener(listener);
-    }
-
-    @Override
-    public Component getUiComponent() {
-        return visiblePanel;
-    }
-
-    private void initializePanel() {
-        visiblePanel = new HeaderPanel();
-        visiblePanel.setHeader(translator.localize(LocaleResources.VM_CPU_TITLE));
-
-        JFreeChart chart = ChartFactory.createTimeSeriesChart(
-                null,
-                translator.localize(LocaleResources.VM_CPU_CHART_TIME_LABEL),
-                translator.localize(LocaleResources.VM_CPU_CHART_LOAD_LABEL),
-                data,
-                false, false, false);
-
-        chart.getXYPlot().getRangeAxis().setLowerBound(0.0);
-
-        JPanel chartPanel = new RecentTimeSeriesChartPanel(new RecentTimeSeriesChartController(chart));
-
-        visiblePanel.setContent(chartPanel);
-    }
-
-    @Override
-    public void addData(List<DiscreteTimeData<? extends Number>> data) {
-        final List<DiscreteTimeData<? extends Number>> copy = new ArrayList<>(data);
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                for (DiscreteTimeData<? extends Number> data: copy) {
-                    RegularTimePeriod period = new FixedMillisecond(data.getTimeInMillis());
-                    if (cpuTimeSeries.getDataItem(period) == null) {
-                        cpuTimeSeries.add(period, data.getData(), false);
-                    }
-                }
-                cpuTimeSeries.fireSeriesChanged();
-            }
-        });
-    }
-
-    @Override
-    public void clearData() {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                cpuTimeSeries.clear();
-            }
-        });
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/VmGcController.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/VmGcController.java	Fri Oct 26 15:32:56 2012 +0200
@@ -67,7 +67,7 @@
 import com.redhat.thermostat.common.model.VmMemoryStat;
 import com.redhat.thermostat.common.model.VmMemoryStat.Generation;
 
-class VmGcController {
+public class VmGcController {
 
     private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
 
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/VmGcPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,245 +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.ui;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.swing.JPanel;
-import javax.swing.SwingUtilities;
-
-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.event.ChartProgressEvent;
-import org.jfree.chart.event.ChartProgressListener;
-import org.jfree.chart.plot.PlotOrientation;
-import org.jfree.chart.plot.XYPlot;
-import org.jfree.chart.renderer.xy.StandardXYBarPainter;
-import org.jfree.chart.renderer.xy.XYBarRenderer;
-import org.jfree.data.RangeType;
-import org.jfree.data.xy.IntervalXYDataset;
-
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.core.views.VmGcView;
-import com.redhat.thermostat.client.locale.LocaleResources;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.model.IntervalTimeData;
-import com.redhat.thermostat.swing.HeaderPanel;
-
-public class VmGcPanel extends VmGcView implements SwingComponent {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private HeaderPanel visiblePanel = new HeaderPanel();
-    private JPanel realPanel = new JPanel();
-
-    private final Map<String, SampledDataset> dataset = new HashMap<>();
-    private final Map<String, JPanel> subPanels = new HashMap<>();
-
-    private final GridBagConstraints gcPanelConstraints;
-
-    public VmGcPanel() {
-        super();
-        initializePanel();
-
-        gcPanelConstraints = new GridBagConstraints();
-        gcPanelConstraints.gridx = 0;
-        gcPanelConstraints.gridy = 0;
-        gcPanelConstraints.fill = GridBagConstraints.BOTH;
-        gcPanelConstraints.weightx = 1;
-        gcPanelConstraints.weighty = 1;
-
-        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
-            @Override
-            public void componentShown(Component component) {
-                notifier.fireAction(Action.VISIBLE);
-            }
-
-            @Override
-            public void componentHidden(Component component) {
-                notifier.fireAction(Action.HIDDEN);
-            }
-        });
-    }
-
-    @Override
-    public void addActionListener(ActionListener<Action> listener) {
-        notifier.addActionListener(listener);
-    }
-
-    @Override
-    public void removeActionListener(ActionListener<Action> listener) {
-        notifier.removeActionListener(listener);
-    }
-
-    @Override
-    public Component getUiComponent() {
-        return visiblePanel;
-    }
-
-    private void initializePanel() {
-        visiblePanel.setContent(realPanel);
-        visiblePanel.setHeader(translator.localize(LocaleResources.VM_GC_TITLE));
-        realPanel.setLayout(new GridBagLayout());
-    }
-
-    private JPanel createCollectorDetailsPanel(IntervalXYDataset collectorData, String title, String units) {
-        JPanel detailsPanel = new JPanel();
-        detailsPanel.setBorder(Components.smallBorder());
-        detailsPanel.setLayout(new BorderLayout());
-
-        detailsPanel.add(Components.header(title), BorderLayout.NORTH);
-
-        JFreeChart chart = ChartFactory.createHistogram(
-            null,
-            translator.localize(LocaleResources.VM_GC_COLLECTOR_CHART_REAL_TIME_LABEL),
-            translator.localize(LocaleResources.VM_GC_COLLECTOR_CHART_GC_TIME_LABEL, units),
-            collectorData,
-            PlotOrientation.VERTICAL,
-            false,
-            false,
-            false);
-
-        ((XYBarRenderer)(chart.getXYPlot().getRenderer())).setBarPainter(new StandardXYBarPainter());
-
-        setupPlotAxes(chart.getXYPlot());
-
-        chart.getXYPlot().setDomainCrosshairLockedOnData(true);
-        chart.getXYPlot().setDomainCrosshairVisible(true);
-
-        final RecentTimeSeriesChartPanel chartPanel = new RecentTimeSeriesChartPanel(new RecentTimeSeriesChartController(chart));
-
-        chart.addProgressListener(new ChartProgressListener() {
-
-            @Override
-            public void chartProgress(ChartProgressEvent event) {
-                if (event.getType() != ChartProgressEvent.DRAWING_FINISHED) {
-                    return;
-                }
-
-                double rangeCrossHairValue = event.getChart().getXYPlot().getRangeCrosshairValue();
-                chartPanel.setDataInformationLabel(String.valueOf(rangeCrossHairValue));
-            }
-        });
-
-        detailsPanel.add(chartPanel, BorderLayout.CENTER);
-
-        return detailsPanel;
-    }
-
-    private void setupPlotAxes(XYPlot plot) {
-        setupDomainAxis(plot);
-        setupRangeAxis(plot);
-    }
-
-    private void setupDomainAxis(XYPlot plot) {
-        plot.setDomainAxis(new DateAxis());
-    }
-
-    private void setupRangeAxis(XYPlot plot) {
-        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
-
-        rangeAxis.setRangeType(RangeType.POSITIVE);
-        rangeAxis.setAutoRange(true);
-        rangeAxis.setAutoRangeMinimumSize(1);
-    }
-
-    @Override
-    public void addChart(final String tag, final String title, final String units) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                SampledDataset newData = new SampledDataset();
-                dataset.put(tag, newData);
-                JPanel subPanel = createCollectorDetailsPanel(newData, title, units);
-                subPanels.put(tag, subPanel);
-                realPanel.add(subPanel, gcPanelConstraints);
-                gcPanelConstraints.gridy++;
-                realPanel.revalidate();
-            }
-        });
-    }
-
-    @Override
-    public void removeChart(final String tag) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                dataset.remove(tag);
-                JPanel subPanel = subPanels.remove(tag);
-                realPanel.remove(subPanel);
-                realPanel.revalidate();
-                gcPanelConstraints.gridy--;
-            }
-        });
-    }
-
-    @Override
-    public void addData(final String tag, List<IntervalTimeData<Double>> data) {
-        final List<IntervalTimeData<Double>> copy = new ArrayList<>(data);
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                SampledDataset series = dataset.get(tag);
-                for (IntervalTimeData<Double> timeData: copy) {
-                    series.add(timeData.getStartTimeInMillis(), timeData.getEndTimeInMillis(), timeData.getData());
-                }
-                series.fireSeriesChanged();
-            }
-        });
-    }
-
-    @Override
-    public void clearData(final String tag) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                SampledDataset series = dataset.get(tag);
-                series.clear();
-            }
-        });
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/VmInformationPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.ui;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-
-import javax.swing.JPanel;
-import javax.swing.JTabbedPane;
-
-import com.redhat.thermostat.client.core.views.UIComponent;
-import com.redhat.thermostat.client.core.views.VmInformationView;
-
-public class VmInformationPanel extends VmInformationView implements SwingComponent {
-
-    private final JTabbedPane tabPane = new JTabbedPane();
-    private JPanel visiblePanel;
-
-    private int tabCount = 0;
-
-    public VmInformationPanel() {
-        super();
-        visiblePanel = new JPanel();
-        visiblePanel.setLayout(new BorderLayout());
-        tabPane.setName("tabPane");
-        visiblePanel.add(tabPane);
-    }
-
-    @Override
-    public void addChildView(String title, UIComponent view) {
-        if (view instanceof SwingComponent) {
-            SwingComponent panel = (SwingComponent)view;
-            tabPane.insertTab(title, null, panel.getUiComponent(), null, tabCount);
-            tabCount++;
-        }
-    }
-
-    public Component getUiComponent() {
-        return visiblePanel;
-    }
-
-    @Override
-    public int getSelectedChildID() {
-        return tabPane.getSelectedIndex();
-    }
-
-    @Override
-    public boolean selectChildID(int id) {
-        if (tabPane.getComponentCount() > id) {
-            tabPane.setSelectedIndex(id);
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public int getNumChildren() {
-        return tabPane.getComponentCount();
-    }
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/VmOverviewPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.ui;
-
-import java.awt.Component;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.JPanel;
-
-import com.redhat.thermostat.client.core.views.VmOverviewView;
-import com.redhat.thermostat.client.internal.ChangeableText;
-import com.redhat.thermostat.client.locale.LocaleResources;
-import com.redhat.thermostat.client.ui.SimpleTable.Section;
-import com.redhat.thermostat.client.ui.SimpleTable.TableEntry;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.swing.HeaderPanel;
-
-public class VmOverviewPanel extends VmOverviewView implements SwingComponent {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-    
-    private HeaderPanel visiblePanel;
-
-    private final ChangeableText pid = new ChangeableText("");
-    private final ChangeableText startTimeStamp = new ChangeableText("");
-    private final ChangeableText stopTimeStamp = new ChangeableText("");
-    private final ChangeableText mainClass = new ChangeableText("");
-    private final ChangeableText javaCommandLine = new ChangeableText("");
-    private final ChangeableText javaHome = new ChangeableText("");
-    private final ChangeableText javaVersion = new ChangeableText("");
-    private final ChangeableText vmNameAndVersion = new ChangeableText("");
-    private final ChangeableText vmArguments = new ChangeableText("");
-
-    public VmOverviewPanel() {
-        super();
-        initializePanel();
-        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
-            @Override
-            public void componentShown(Component component) {
-                notifier.fireAction(Action.VISIBLE);
-            }
-
-            @Override
-            public void componentHidden(Component component) {
-                notifier.fireAction(Action.HIDDEN);
-            }
-        });
-    }
-
-    @Override
-    public void addActionListener(ActionListener<Action> listener) {
-        notifier.addActionListener(listener);
-    }
-
-    @Override
-    public void removeActionListener(ActionListener<Action> listener) {
-        notifier.removeActionListener(listener);
-    }
-
-    @Override
-    public void setVmPid(String pid) {
-        this.pid.setText(pid);
-    }
-
-    @Override
-    public void setVmStartTimeStamp(String timeStamp) {
-        this.startTimeStamp.setText(timeStamp);
-    }
-
-    @Override
-    public void setVmStopTimeStamp(String timeStamp) {
-        this.stopTimeStamp.setText(timeStamp);
-    }
-
-    @Override
-    public void setMainClass(String mainClass) {
-        this.mainClass.setText(mainClass);
-    }
-
-    @Override
-    public void setJavaCommandLine(String javaCommandLine) {
-        this.javaCommandLine.setText(javaCommandLine);
-    }
-
-    @Override
-    public void setJavaHome(String javaHome) {
-        this.javaHome.setText(javaHome);
-
-    }
-
-    @Override
-    public void setJavaVersion(String javaVersion) {
-        this.javaVersion.setText(javaVersion);
-    }
-
-    @Override
-    public void setVmNameAndVersion(String vmNameAndVersion) {
-        this.vmNameAndVersion.setText(vmNameAndVersion);
-    }
-
-    @Override
-    public void setVmArguments(String vmArguments) {
-        this.vmArguments.setText(vmArguments);
-    }
-
-    @Override
-    public void setVmInfo(String string) {
-        // no-op
-    }
-
-    @Override
-    public Component getUiComponent() {
-        return visiblePanel;
-    }
-
-    private void initializePanel() {
-        visiblePanel = new HeaderPanel();
-
-        visiblePanel.setHeader(translator.localize(LocaleResources.VM_INFO_TITLE));
-
-        TableEntry entry;
-        List<Section> allSections = new ArrayList<Section>();
-
-        Section processSection = new Section(translator.localize(LocaleResources.VM_INFO_SECTION_PROCESS));
-        allSections.add(processSection);
-
-        entry = new TableEntry(translator.localize(LocaleResources.VM_INFO_PROCESS_ID), pid);
-        processSection.add(entry);
-        entry = new TableEntry(translator.localize(LocaleResources.VM_INFO_START_TIME), startTimeStamp);
-        processSection.add(entry);
-        entry = new TableEntry(translator.localize(LocaleResources.VM_INFO_STOP_TIME), stopTimeStamp);
-        processSection.add(entry);
-
-        Section javaSection = new Section(translator.localize(LocaleResources.VM_INFO_SECTION_JAVA));
-        allSections.add(javaSection);
-
-        entry = new TableEntry(translator.localize(LocaleResources.VM_INFO_MAIN_CLASS), mainClass);
-        javaSection.add(entry);
-        entry = new TableEntry(translator.localize(LocaleResources.VM_INFO_COMMAND_LINE), javaCommandLine);
-        javaSection.add(entry);
-        entry = new TableEntry(translator.localize(LocaleResources.VM_INFO_JAVA_VERSION), javaVersion);
-        javaSection.add(entry);
-        entry = new TableEntry(translator.localize(LocaleResources.VM_INFO_VM), vmNameAndVersion);
-        javaSection.add(entry);
-        entry = new TableEntry(translator.localize(LocaleResources.VM_INFO_VM_ARGUMENTS), vmArguments);
-        javaSection.add(entry);
-
-        SimpleTable simpleTable = new SimpleTable();
-        JPanel table = simpleTable.createTable(allSections);
-        table.setBorder(Components.smallBorder());
-        visiblePanel.setContent(table);
-    }
-}
Binary file client/core/src/main/resources/duke.png has changed
--- a/client/core/src/test/java/com/redhat/thermostat/client/internal/GUIClientCommandTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +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.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isNotNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.Dictionary;
-
-import org.apache.commons.cli.Options;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.osgi.framework.BundleContext;
-
-import com.redhat.thermostat.client.internal.GUIClientCommand;
-import com.redhat.thermostat.client.internal.Main;
-import com.redhat.thermostat.client.osgi.service.ApplicationService;
-import com.redhat.thermostat.client.osgi.service.ContextAction;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandContextFactory;
-import com.redhat.thermostat.common.cli.CommandException;
-
-public class GUIClientCommandTest {
-
-    private GUIClientCommand cmd;
-    private Main clientMain;
-
-    @Before
-    public void setUp() {
-        clientMain = mock(Main.class);
-        cmd = new GUIClientCommand(clientMain);
-    }
-
-    @After
-    public void tearDown() {
-        cmd = null;
-        clientMain = null;
-    }
-
-    @Test
-    public void testRun() throws CommandException {
-        BundleContext bCtx = mock(BundleContext.class);
-        CommandContextFactory cmdCtxFactory = mock(CommandContextFactory.class);
-
-        CommandContext cmdCtx = mock(CommandContext.class);
-        when(cmdCtx.getCommandContextFactory()).thenReturn(cmdCtxFactory);
-
-        cmd.setBundleContext(bCtx);
-        cmd.run(cmdCtx);
-
-        verify(clientMain).run();
-        verify(bCtx).registerService(eq(ApplicationService.class.getName()), isNotNull(), any(Dictionary.class));
-        verify(bCtx).registerService(eq(ContextAction.class.getName()), isNotNull(), any(Dictionary.class));
-    }
-
-    @Test
-    public void testName() {
-        assertEquals("gui", cmd.getName());
-    }
-
-    @Test
-    public void testDescAndUsage() {
-        assertNotNull(cmd.getDescription());
-        assertNotNull(cmd.getUsage());
-    }
-
-    @Test
-    public void testRequiresStorage() {
-        assertFalse(cmd.isStorageRequired());
-    }
-
-    @Test
-    public void testOptions() {
-        Options options = cmd.getOptions();
-        assertNotNull(options);
-        assertEquals(0, options.getOptions().size());
-    }
-}
--- a/client/core/src/test/java/com/redhat/thermostat/client/internal/HostIconDecoratorTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +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.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-
-import java.awt.image.BufferedImage;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-
-import javax.imageio.ImageIO;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.client.core.HostFilter;
-import com.redhat.thermostat.client.ui.Decorator;
-import com.redhat.thermostat.common.dao.HostRef;
-
-public class HostIconDecoratorTest {
-
-    @Test
-    public void verifyFilter() {
-        HostIconDecorator decorator = new HostIconDecorator();
-
-        HostFilter filter = decorator.getFilter();
-        HostRef aHost = mock(HostRef.class);
-
-        assertTrue(filter.matches(aHost));
-    }
-
-    @Test
-    public void verifyHostDecoratorDoesNotModifyLabel() {
-        HostIconDecorator iconDecorator = new HostIconDecorator();
-
-        Decorator decorator = iconDecorator.getDecorator();
-
-        String INPUT = "testfoobarbaz";
-
-        assertEquals(INPUT, decorator.getLabel(INPUT));
-    }
-
-    @Test
-    public void verifyHostDecoratorHasAnIcon() throws IOException {
-        HostIconDecorator iconDecorator = new HostIconDecorator();
-
-        Decorator decorator = iconDecorator.getDecorator();
-
-        BufferedImage icon = ImageIO.read(new ByteArrayInputStream(decorator.getIconDescriptor().getData().array()));
-
-        assertNotNull(icon);
-    }
-}
--- a/client/core/src/test/java/com/redhat/thermostat/client/internal/MainTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,202 +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.internal;
-
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.concurrent.ExecutorService;
-
-import javax.swing.SwingUtilities;
-
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import com.redhat.thermostat.client.osgi.service.ApplicationService;
-import com.redhat.thermostat.client.ui.MainWindowController;
-import com.redhat.thermostat.client.ui.UiFacadeFactory;
-import com.redhat.thermostat.common.TimerFactory;
-import com.redhat.thermostat.common.dao.DAOFactory;
-import com.redhat.thermostat.common.storage.Connection;
-import com.redhat.thermostat.common.storage.Connection.ConnectionListener;
-import com.redhat.thermostat.common.storage.Connection.ConnectionStatus;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-
-public class MainTest {
-
-    private ExecutorService executorService;
-    private OSGIUtils serviceProvider;
-
-    private MainWindowController mainWindowController;
-    private UiFacadeFactory uiFactory;
-
-    private Connection connection;
-    private ArgumentCaptor<ConnectionListener> connectionListenerCaptor;
-
-    private DAOFactory daoFactory;
-
-    private TimerFactory timerFactory;
-
-    @Before
-    public void setUp() {
-        ApplicationService appService = mock(ApplicationService.class);
-
-        executorService = mock(ExecutorService.class);
-        doAnswer(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                Runnable runnable = (Runnable) invocation.getArguments()[0];
-                runnable.run();
-                return null;
-            }
-        }).when(executorService).execute(isA(Runnable.class));
-
-        when(appService.getApplicationExecutor()).thenReturn(executorService);
-
-        serviceProvider = mock(OSGIUtils.class);
-        when(serviceProvider.getService(ApplicationService.class)).thenReturn(appService);
-
-        mainWindowController = mock(MainWindowController.class);
-
-        uiFactory = mock(UiFacadeFactory.class);
-        when(uiFactory.getMainWindow()).thenReturn(mainWindowController);
-
-        connection = mock(Connection.class);
-        connectionListenerCaptor = ArgumentCaptor.forClass(ConnectionListener.class);
-        doNothing().when(connection).addListener(connectionListenerCaptor.capture());
-
-        daoFactory = mock(DAOFactory.class);
-        when(daoFactory.getConnection()).thenReturn(connection);
-
-        timerFactory = mock(TimerFactory.class);
-    }
-
-    /**
-     * Handle all outstanding EDT events by posting a no-op event and waiting
-     * until it completes.
-     */
-    private void handleAllEdtEvents() throws Exception {
-        SwingUtilities.invokeAndWait(new Runnable() {
-            @Override
-            public void run() {
-                /* NO-OP */
-            }
-        });
-    }
-
-    @Test
-    public void verifyRunWaitsForShutdown() throws Exception {
-        Main main = new Main(serviceProvider, uiFactory, daoFactory, timerFactory);
-
-        main.run();
-
-        handleAllEdtEvents();
-
-        verify(uiFactory).awaitShutdown();
-    }
-
-    @Test
-    public void verifyConnectionIsMade() throws Exception {
-        Main main = new Main(serviceProvider, uiFactory, daoFactory, timerFactory);
-
-        main.run();
-
-        handleAllEdtEvents();
-
-        verify(connection).connect();
-
-    }
-
-    @Test
-    public void verifySuccessfulConnectionTriggersMainWindowToBeShown() throws Exception {
-        Main main = new Main(serviceProvider, uiFactory, daoFactory, timerFactory);
-
-        main.run();
-
-        handleAllEdtEvents();
-
-        ConnectionListener connectionListener = connectionListenerCaptor.getValue();
-        connectionListener.changed(ConnectionStatus.CONNECTED);
-
-        handleAllEdtEvents();
-
-        verify(mainWindowController).showMainMainWindow();
-    }
-
-    @Test
-    public void verifySuccessfulConnectionRegistersDAOs() throws Exception {
-
-        Main main = new Main(serviceProvider, uiFactory, daoFactory, timerFactory);
-
-        main.run();
-
-        handleAllEdtEvents();
-
-        ConnectionListener connectionListener = connectionListenerCaptor.getValue();
-        connectionListener.changed(ConnectionStatus.CONNECTED);
-
-        handleAllEdtEvents();
-
-        verify(daoFactory).registerDAOsAndStorageAsOSGiServices();
-    }
-
-    @Ignore("this prompts the user with some gui")
-    @Test
-    public void verifyFailedConnectionTriggersShutdown() throws Exception {
-
-        Main main = new Main(serviceProvider, uiFactory, daoFactory, timerFactory);
-
-        main.run();
-
-        handleAllEdtEvents();
-
-        ConnectionListener connectionListener = connectionListenerCaptor.getValue();
-        connectionListener.changed(ConnectionStatus.FAILED_TO_CONNECT);
-
-        handleAllEdtEvents();
-
-        verify(uiFactory).shutdown();
-    }
-}
--- a/client/core/src/test/java/com/redhat/thermostat/client/internal/MainWindowControllerImplTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,561 +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.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.awt.event.MouseEvent;
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.osgi.framework.BundleException;
-
-import com.redhat.thermostat.client.core.VmFilter;
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.osgi.service.MenuAction;
-import com.redhat.thermostat.client.osgi.service.VMContextAction;
-import com.redhat.thermostat.client.osgi.service.VmDecorator;
-import com.redhat.thermostat.client.ui.HostVmFilter;
-import com.redhat.thermostat.client.ui.SummaryController;
-import com.redhat.thermostat.client.ui.UiFacadeFactory;
-import com.redhat.thermostat.client.ui.VmInformationController;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.HostsVMsLoader;
-import com.redhat.thermostat.common.ThermostatExtensionRegistry;
-import com.redhat.thermostat.common.Timer;
-import com.redhat.thermostat.common.ThermostatExtensionRegistry.Action;
-import com.redhat.thermostat.common.Timer.SchedulingType;
-import com.redhat.thermostat.common.TimerFactory;
-import com.redhat.thermostat.common.appctx.ApplicationContext;
-import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
-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.model.VmInfo;
-import com.redhat.thermostat.test.Bug;
-
-public class MainWindowControllerImplTest {
-
-    private ActionListener<MainView.Action> l;
-
-    private MainWindowControllerImpl controller;
-
-    private UiFacadeFactory uiFacadeFactory;
-    
-    private MainView view;
-
-    private Timer mainWindowTimer;
-
-    private HostInfoDAO mockHostsDAO;
-    private VmInfoDAO mockVmsDAO;
-
-    private VMContextAction action1;
-    private VMContextAction action2;
-
-    private HostFilterRegistry hostFilterRegistry;
-    private VmFilterRegistry vmFilterRegistry;
-    private HostTreeDecoratorRegistry hostDecoratorRegistry;
-    private VMTreeDecoratorRegistry vmDecoratorRegistry;
-    private VMInformationRegistry vmInfoRegistry;
-    private MenuRegistry menus;
-    
-    @SuppressWarnings("unused")
-    private ActionListener<ThermostatExtensionRegistry.Action> hostFiltersListener;
-    @SuppressWarnings("unused")
-    private ActionListener<ThermostatExtensionRegistry.Action> vmFiltersListener;
-    private ActionListener<ThermostatExtensionRegistry.Action> decoratorsListener;
-    
-    @BeforeClass
-    public static void setUpOnce() {
-        // TODO remove when controller uses mocked objects rather than real swing objects
-        FailOnThreadViolationRepaintManager.install();
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" }) // ActionListener fluff
-    @Before
-    public void setUp() throws Exception {
-        ApplicationContextUtil.resetApplicationContext();
-
-        // Setup timers
-        mainWindowTimer = mock(Timer.class);
-        Timer otherTimer = mock(Timer.class); // FIXME needed for SummaryView; remove later
-        TimerFactory timerFactory = mock(TimerFactory.class);
-        when(timerFactory.createTimer()).thenReturn(mainWindowTimer).thenReturn(otherTimer);
-        ApplicationContext.getInstance().setTimerFactory(timerFactory);
-
-        SummaryController summaryController = mock(SummaryController.class);
-
-        uiFacadeFactory = mock(UiFacadeFactory.class);
-        
-        when(uiFacadeFactory.getSummary()).thenReturn(summaryController);
-
-        mockHostsDAO = mock(HostInfoDAO.class);
-        mockVmsDAO = mock(VmInfoDAO.class);
-
-        // Setup View
-        view = mock(MainView.class);
-        ArgumentCaptor<ActionListener> grabListener = ArgumentCaptor.forClass(ActionListener.class);
-        doNothing().when(view).addActionListener(grabListener.capture());
-        
-        RegistryFactory registryFactory = mock(RegistryFactory.class);
-        hostFilterRegistry = mock(HostFilterRegistry.class);
-        vmFilterRegistry = mock(VmFilterRegistry.class);
-        hostDecoratorRegistry = mock(HostTreeDecoratorRegistry.class);
-        vmDecoratorRegistry = mock(VMTreeDecoratorRegistry.class);
-        vmInfoRegistry = mock(VMInformationRegistry.class);
-        menus = mock(MenuRegistry.class);
-
-        when(registryFactory.createMenuRegistry()).thenReturn(menus);
-        when(registryFactory.createHostTreeDecoratorRegistry()).thenReturn(hostDecoratorRegistry);
-        when(registryFactory.createVMTreeDecoratorRegistry()).thenReturn(vmDecoratorRegistry);
-        when(registryFactory.createHostFilterRegistry()).thenReturn(hostFilterRegistry);
-        when(registryFactory.createVmFilterRegistry()).thenReturn(vmFilterRegistry);
-        when(registryFactory.createVMInformationRegistry()).thenReturn(vmInfoRegistry);
-        
-        ArgumentCaptor<ActionListener> grabHostFiltersListener = ArgumentCaptor.forClass(ActionListener.class);
-        doNothing().when(hostFilterRegistry).addActionListener(grabHostFiltersListener.capture());
-
-        ArgumentCaptor<ActionListener> grabVmFiltersListener = ArgumentCaptor.forClass(ActionListener.class);
-        doNothing().when(vmFilterRegistry).addActionListener(grabVmFiltersListener.capture());
-
-        ArgumentCaptor<ActionListener> grabDecoratorsListener = ArgumentCaptor.forClass(ActionListener.class);
-        doNothing().when(vmDecoratorRegistry).addActionListener(grabDecoratorsListener.capture());
-        
-        ArgumentCaptor<ActionListener> grabInfoRegistry = ArgumentCaptor.forClass(ActionListener.class);
-        doNothing().when(vmInfoRegistry).addActionListener(grabInfoRegistry.capture());
-
-        setUpVMContextActions();
-
-        controller = new MainWindowControllerImpl(uiFacadeFactory, view, registryFactory, mockHostsDAO, mockVmsDAO);
-        l = grabListener.getValue();
-        
-        hostFiltersListener = grabHostFiltersListener.getValue();
-        vmFiltersListener = grabVmFiltersListener.getValue();
-        decoratorsListener = grabDecoratorsListener.getValue();
-    }
-
-    private void setUpVMContextActions() {
-        action1 = mock(VMContextAction.class);
-        VmFilter action1Filter = mock(VmFilter.class);
-        when(action1Filter.matches(isA(VmRef.class))).thenReturn(true);
-
-        when(action1.getName()).thenReturn("action1");
-        when(action1.getDescription()).thenReturn("action1desc");
-        when(action1.getFilter()).thenReturn(action1Filter);
-        
-        action2 = mock(VMContextAction.class);
-        VmFilter action2Filter = mock(VmFilter.class);
-        when(action2Filter.matches(isA(VmRef.class))).thenReturn(false);
-
-        when(action2.getName()).thenReturn("action2");
-        when(action2.getDescription()).thenReturn("action2desc");
-        when(action2.getFilter()).thenReturn(action2Filter);
-        
-        Collection<VMContextAction> actions = new ArrayList<>();
-        actions.add(action1);
-        actions.add(action2);
-        
-        when(uiFacadeFactory.getVMContextActions()).thenReturn(actions);
-    }
-
-    @After
-    public void tearDown() {
-        view = null;
-        controller = null;
-        mockHostsDAO = null;
-        mockVmsDAO = null;
-        l = null;
-        ApplicationContextUtil.resetApplicationContext();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void verifyDecoratorsAdded() {
-
-        List<VmDecorator> currentDecoratros = controller.getVmTreeDecorators();
-        assertEquals(0, currentDecoratros.size());
-        
-        ActionEvent<ThermostatExtensionRegistry.Action> event =
-                new ActionEvent<ThermostatExtensionRegistry.Action>(vmDecoratorRegistry,
-                        ThermostatExtensionRegistry.Action.SERVICE_ADDED);
-        
-        VmDecorator payload = mock(VmDecorator.class);
-        event.setPayload(payload);
-        
-        decoratorsListener.actionPerformed(event);
-
-        currentDecoratros = controller.getVmTreeDecorators();
-        assertEquals(1, currentDecoratros.size());
-        assertEquals(payload, currentDecoratros.get(0));
-        
-        verify(view).updateTree(any(List.class), isA(List.class), isA(List.class), any(List.class), any(HostsVMsLoader.class));
-    }
-    
-    @Test
-    public void verifyThatHiddenEventStopsController() {
-
-        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HIDDEN));
-
-        verify(mainWindowTimer).stop();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void verifyThatHostsVmsFilterChangeUpdatesTree() {
-
-        when(view.getHostVmTreeFilterText()).thenReturn("test");
-
-        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_TREE_FILTER));
-
-        verify(view).updateTree(isA(List.class), isA(List.class), isA(List.class), isA(List.class), isA(HostsVMsLoader.class));
-    }
-    
-    @Test
-    public void verifyTimerGetsStartedOnBecomingVisible() {
-        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.VISIBLE));
-
-        verify(mainWindowTimer).setDelay(3);
-        verify(mainWindowTimer).setTimeUnit(TimeUnit.SECONDS);
-        verify(mainWindowTimer).setSchedulingType(SchedulingType.FIXED_RATE);
-        verify(mainWindowTimer).start();
-    }
-
-    @Test
-    public void verifyShowMainWindowActuallyCallsView() {
-        controller.showMainMainWindow();
-        verify(view).showMainWindow();
-    }
-
-    @Test
-    public void verifySubViewIsSetByDefault() throws InvocationTargetException, InterruptedException {
-        verify(view).setSubView(any(BasicView.class));
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void verifyUpdateHostsVMsLoadsCorrectHosts() {
-
-        Collection<HostRef> expectedHosts = new ArrayList<>();
-        expectedHosts.add(new HostRef("123", "fluffhost1"));
-        expectedHosts.add(new HostRef("456", "fluffhost2"));
-
-        when(mockHostsDAO.getAliveHosts()).thenReturn(expectedHosts);
-
-        controller.doUpdateTreeAsync();
-
-        ArgumentCaptor<HostsVMsLoader> arg = ArgumentCaptor.forClass(HostsVMsLoader.class);
-        verify(view).updateTree(isA(List.class), isA(List.class), isA(List.class), isA(List.class), arg.capture());
-        HostsVMsLoader loader = arg.getValue();
-
-        Collection<HostRef> actualHosts = loader.getHosts();
-        assertEqualCollection(expectedHosts, actualHosts);
-    }
-    
-    @SuppressWarnings("unchecked")
-    @Test
-    public void verifyHistoryModeUpdateHostsVMCorrectly() {
-
-        Collection<HostRef> liveHost = new ArrayList<>();
-        liveHost.add(new HostRef("123", "fluffhost1"));
-        liveHost.add(new HostRef("456", "fluffhost2"));
-
-        Collection<HostRef> allHosts = new ArrayList<>();
-        allHosts.addAll(liveHost);
-        allHosts.add(new HostRef("789", "fluffhost3"));
-
-        when(mockHostsDAO.getAliveHosts()).thenReturn(liveHost);
-        when(mockHostsDAO.getHosts()).thenReturn(allHosts);
-
-        controller.doUpdateTreeAsync();
-
-        ArgumentCaptor<HostsVMsLoader> arg = ArgumentCaptor.forClass(HostsVMsLoader.class);
-        verify(view).updateTree(isA(List.class), isA(List.class), isA(List.class), isA(List.class), arg.capture());
-        HostsVMsLoader loader = arg.getValue();
-
-        Collection<HostRef> actualHosts = loader.getHosts();
-        assertEqualCollection(liveHost, actualHosts);
-
-        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.SWITCH_HISTORY_MODE));
-        ArgumentCaptor<HostsVMsLoader> argCaptor = ArgumentCaptor.forClass(HostsVMsLoader.class);
-        // actionPerformed triggers updateTree
-        verify(view, times(2)).updateTree(isA(List.class), isA(List.class), isA(List.class), isA(List.class), argCaptor.capture());
-        loader = argCaptor.getValue();
-
-        actualHosts = loader.getHosts();
-        assertEqualCollection(allHosts, actualHosts);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void verifyUpdateHostsVMsLoadsCorrectVMs() {
-
-        Collection<VmRef> expectedVMs = new ArrayList<>();
-        HostRef host = new HostRef("123", "fluffhost1");
-        expectedVMs.add(new VmRef(host, 123, "vm1"));
-        expectedVMs.add(new VmRef(host, 456, "vm2"));
-
-        when(mockVmsDAO.getVMs(any(HostRef.class))).thenReturn(expectedVMs);
-
-        controller.doUpdateTreeAsync();
-
-        ArgumentCaptor<HostsVMsLoader> arg = ArgumentCaptor.forClass(HostsVMsLoader.class);
-        verify(view).updateTree(isA(List.class), isA(List.class), isA(List.class), isA(List.class), arg.capture());
-        HostsVMsLoader loader = arg.getValue();
-
-        Collection<VmRef> actualVMs = loader.getVMs(host);
-        assertEqualCollection(expectedVMs, actualVMs);
-    }
-
-    @Test
-    public void verifyUpdateHostsVMsLoadsCorrectVMWithFilter() {
-
-        VmRef ref1 = mock(VmRef.class);
-        when(ref1.getStringID()).thenReturn("test1");
-        when(ref1.getName()).thenReturn("test1");
-        
-        VmRef ref2 = mock(VmRef.class);
-        when(ref2.getStringID()).thenReturn("test2");
-        when(ref2.getName()).thenReturn("test2");
-        
-        controller.setHostVmTreeFilter("test1");
-                
-        HostVmFilter filter = controller.getSearchFilter();
-        assertTrue(filter.matches(ref1));
-        assertFalse(filter.matches(ref2));
-    }
-    
-    private void assertEqualCollection(Collection<?> expected, Collection<?> actual) {
-        assertEquals(expected.size(), actual.size());
-        assertTrue(expected.containsAll(actual));
-    }
-
-    @Test
-    @Bug(id="954",
-         summary="Thermostat GUI client should remember my last panel selected",
-         url="http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=954")
-    public void verifyOpenSameHostVMTab() throws Exception {
-
-        VmRef vmRef = mock(VmRef.class);
-        when(vmRef.getName()).thenReturn("testvm");
-        when(vmRef.getIdString()).thenReturn("testvmid");
-        HostRef ref = mock(HostRef.class);
-        when(ref.getAgentId()).thenReturn("agentId");
-        when(vmRef.getAgent()).thenReturn(ref);
-        
-        when(view.getSelectedHostOrVm()).thenReturn(vmRef);
-
-        VmInformationController vmInformationController = mock(VmInformationController.class);
-        when(vmInformationController.getSelectedChildID()).thenReturn(3);
-        when(uiFacadeFactory.getVmController(any(VmRef.class))).thenReturn(vmInformationController);
-        when(vmInformationController.selectChildID(anyInt())).thenReturn(true);
-
-        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
-
-        ArgumentCaptor<Integer> arg = ArgumentCaptor.forClass(Integer.class);
-        verify(vmInformationController).selectChildID(arg.capture());
-        verify(vmInformationController, times(0)).getSelectedChildID();
-
-        int id = arg.getValue();
-
-        assertEquals(0, id);
-
-        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
-
-        arg = ArgumentCaptor.forClass(Integer.class);
-        verify(vmInformationController, times(1)).getSelectedChildID();
-        verify(vmInformationController, times(2)).selectChildID(arg.capture());
-        id = arg.getValue();
-
-        assertEquals(3, id);
-    }
-    
-    @Test
-    public void verifyOpenSameHostVMTab2() {
-        
-        VmRef vmRef1 = mock(VmRef.class);
-        VmRef vmRef2 = mock(VmRef.class);
-        when(view.getSelectedHostOrVm()).thenReturn(vmRef1).thenReturn(vmRef1).thenReturn(vmRef2).thenReturn(vmRef1);
-
-        when(vmRef1.getName()).thenReturn("testvm");
-        when(vmRef1.getIdString()).thenReturn("testvmid");
-        HostRef ref = mock(HostRef.class);
-        when(ref.getAgentId()).thenReturn("agentId");
-        when(vmRef1.getAgent()).thenReturn(ref);
-        
-        when(vmRef2.getName()).thenReturn("testvm");
-        when(vmRef2.getIdString()).thenReturn("testvmid");
-        when(vmRef2.getAgent()).thenReturn(ref);
-        
-        VmInformationController vmInformationController1 = mock(VmInformationController.class);
-        VmInformationController vmInformationController2 = mock(VmInformationController.class);
-        
-        when(vmInformationController1.getSelectedChildID()).thenReturn(2).thenReturn(2);
-        when(vmInformationController2.getSelectedChildID()).thenReturn(3);
-        
-        when(vmInformationController1.selectChildID(0)).thenReturn(true);
-        when(vmInformationController1.selectChildID(2)).thenReturn(true);
-        when(vmInformationController1.selectChildID(3)).thenReturn(false);
-        
-        when(vmInformationController2.selectChildID(0)).thenReturn(true);
-        when(vmInformationController2.selectChildID(2)).thenReturn(true);
-        when(vmInformationController2.selectChildID(3)).thenReturn(true);
-        
-        when(uiFacadeFactory.getVmController(any(VmRef.class))).
-                             thenReturn(vmInformationController1).
-                             thenReturn(vmInformationController2).
-                             thenReturn(vmInformationController2).
-                             thenReturn(vmInformationController1);
-
-        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
-
-        ArgumentCaptor<Integer> arg = ArgumentCaptor.forClass(Integer.class);
-        verify(vmInformationController1).selectChildID(arg.capture());
-        verify(vmInformationController1, times(0)).getSelectedChildID();
-
-        int id = arg.getValue();
-
-        assertEquals(0, id);
-
-        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
-
-        arg = ArgumentCaptor.forClass(Integer.class);
-        verify(vmInformationController1).getSelectedChildID();
-        verify(vmInformationController2, times(1)).selectChildID(arg.capture());
-        id = arg.getValue();
-
-        assertEquals(2, id);
-        
-        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
-
-        arg = ArgumentCaptor.forClass(Integer.class);
-        verify(vmInformationController2, times(1)).getSelectedChildID();
-        verify(vmInformationController2, times(2)).selectChildID(arg.capture());
-        id = arg.getValue();
-
-        assertEquals(3, id);
-        
-        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
-
-        arg = ArgumentCaptor.forClass(Integer.class);
-        verify(vmInformationController2, times(2)).getSelectedChildID();
-        verify(vmInformationController1, times(3)).selectChildID(arg.capture());
-        id = arg.getValue();
-
-        assertEquals(2, id);
-    }
-    
-    @Test
-    public void verityVMActionsAreShown() {
-        VmInfo vmInfo = new VmInfo(0, 1, 2, null, null, null, null, null, null, null, null, null, null, null);
-        when(mockVmsDAO.getVmInfo(isA(VmRef.class))).thenReturn(vmInfo);
-
-        VmRef ref = mock(VmRef.class);
-        when(view.getSelectedHostOrVm()).thenReturn(ref);
-
-        MouseEvent uiEvent = mock(MouseEvent.class);
-        ActionEvent<MainView.Action> viewEvent = new ActionEvent<>(view, MainView.Action.SHOW_VM_CONTEXT_MENU);
-        viewEvent.setPayload(uiEvent);
-
-        l.actionPerformed(viewEvent);
-
-        verify(view).showVMContextActions(Arrays.asList(action1), uiEvent);
-    }
-    
-    @Test
-    public void verityVMActionsAreExecuted() {
-
-        VmRef vmRef = mock(VmRef.class);
-        when(view.getSelectedHostOrVm()).thenReturn(vmRef);
-
-        ActionEvent<MainView.Action> event = new ActionEvent<>(view, MainView.Action.VM_CONTEXT_ACTION);
-        event.setPayload(action1);
-        l.actionPerformed(event);
-        
-        verify(action1, times(1)).execute(any(VmRef.class));
-        verify(action2, times(0)).execute(any(VmRef.class));
-    }
-
-    @Test
-    public void verifyMenuItems() {
-        
-        ActionListener<ThermostatExtensionRegistry.Action> menuListener = controller.getMenuListener();
-
-        MenuAction action = mock(MenuAction.class);
-        when(action.getName()).thenReturn("Test1");
-
-        ActionEvent<Action> addEvent = new ActionEvent<ThermostatExtensionRegistry.Action>(
-        		menus, ThermostatExtensionRegistry.Action.SERVICE_ADDED);
-        addEvent.setPayload(action);
-        menuListener.actionPerformed(addEvent);
-        verify(view).addMenu(action);
-
-        ActionEvent<Action> removeEvent = new ActionEvent<ThermostatExtensionRegistry.Action>(menus, ThermostatExtensionRegistry.Action.SERVICE_REMOVED);
-        removeEvent.setPayload(action);
-        menuListener.actionPerformed(removeEvent);
-        verify(view).removeMenu(action);
-    }
-
-   @Test
-   public void testOSGiFrameworkShutdown() throws BundleException {
-
-       l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.SHUTDOWN));
-
-       verify(uiFacadeFactory).shutdown();
-   }
-}
--- a/client/core/src/test/java/com/redhat/thermostat/client/internal/MenuRegistryTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +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.internal;
-
-import static org.junit.Assert.*;
-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 org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceEvent;
-import org.osgi.framework.ServiceListener;
-import org.osgi.framework.ServiceReference;
-
-import com.redhat.thermostat.client.internal.MenuRegistry;
-import com.redhat.thermostat.client.osgi.service.MenuAction;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.ThermostatExtensionRegistry;
-
-public class MenuRegistryTest {
-
-    @Test
-    public void verifyMenuRegistryReactsToMenuActions() throws InvalidSyntaxException {
-        ArgumentCaptor<ServiceListener> serviceListenerCaptor = ArgumentCaptor.forClass(ServiceListener.class);
-        ArgumentCaptor<String> filterCaptor = ArgumentCaptor.forClass(String.class);
-
-        ActionListener<ThermostatExtensionRegistry.Action> menuListener = mock(ActionListener.class);
-        MenuAction menuAction = mock(MenuAction.class);
-
-        BundleContext context = mock(BundleContext.class);
-        doNothing().when(context).addServiceListener(serviceListenerCaptor.capture(), filterCaptor.capture());
-
-        ServiceReference ref = mock(ServiceReference.class);
-        when(ref.getProperty("objectClass")).thenReturn(MenuAction.class.getName());
-
-        when(context.getService(ref)).thenReturn(menuAction);
-
-        MenuRegistry registry = new MenuRegistry(context);
-        registry.addActionListener(menuListener);
-        registry.start();
-
-        ServiceListener serviceListener = serviceListenerCaptor.getValue();
-        serviceListener.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, ref));
-
-        ArgumentCaptor<ActionEvent> eventCaptor = ArgumentCaptor.forClass(ActionEvent.class);
-        serviceListener.serviceChanged(new ServiceEvent(ServiceEvent.UNREGISTERING, ref));
-
-        verify(menuListener, times(2)).actionPerformed(eventCaptor.capture());
-
-        ActionEvent firstEvent = eventCaptor.getAllValues().get(0);
-        ActionEvent secondEvent = eventCaptor.getAllValues().get(1);
-
-        assertEquals(ThermostatExtensionRegistry.Action.SERVICE_ADDED, firstEvent.getActionId());
-        assertEquals(ThermostatExtensionRegistry.Action.SERVICE_REMOVED, secondEvent.getActionId());
-
-    }
-}
--- a/client/core/src/test/java/com/redhat/thermostat/client/internal/SearchFieldSwingViewTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,198 +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.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import java.awt.FlowLayout;
-
-import javax.swing.JButton;
-import javax.swing.JFrame;
-
-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.JButtonFixture;
-import org.fest.swing.fixture.JTextComponentFixture;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.runner.RunWith;
-
-import com.redhat.thermostat.client.ui.SearchFieldSwingView;
-import com.redhat.thermostat.client.ui.SearchFieldView;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-
-@RunWith(CacioFESTRunner.class)
-public class SearchFieldSwingViewTest {
-
-    private final String OTHER_COMPONENT_NAME = "other";
-
-    private JFrame frame;
-    private SearchFieldSwingView searchField;
-    private JButton otherComponent;
-    private FrameFixture frameFixture;
-
-    @BeforeClass
-    public static void setUpOnce() {
-        FailOnThreadViolationRepaintManager.install();
-    }
-
-    @Before
-    public void setUp() {
-        GuiActionRunner.execute(new GuiTask() {
-
-
-            @Override
-            protected void executeInEDT() throws Throwable {
-                frame = new JFrame();
-                frame.setLayout(new FlowLayout());
-                searchField = new SearchFieldSwingView();
-                frame.add(searchField);
-                otherComponent = new JButton();
-                otherComponent.setName(OTHER_COMPONENT_NAME);
-                frame.add(otherComponent);
-            }
-        });
-        frameFixture = new FrameFixture(frame);
-    }
-
-    @After
-    public void tearDown() {
-        frameFixture.cleanUp();
-        frameFixture = null;
-    }
-
-    @Test
-    public void verifyInitialSearchString() {
-        frameFixture.show();
-
-        assertEquals("", searchField.getSearchText());
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void verifyLabelShownByDefault() {
-        final String LABEL = "search label to help users";
-        searchField.setLabel(LABEL);
-
-        frameFixture.show();
-        JTextComponentFixture textBox = frameFixture.textBox(SearchFieldView.VIEW_NAME);
-        assertEquals(LABEL, textBox.text());
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void verifyLabelHiddenAndShownProperly() {
-        final String LABEL = "search label to help users";
-        final String USER_TEXT = "java";
-        searchField.setLabel(LABEL);
-
-        frameFixture.show();
-        JTextComponentFixture textBox = frameFixture.textBox(SearchFieldView.VIEW_NAME);
-        assertEquals(LABEL, textBox.text());
-
-        textBox.enterText(USER_TEXT);
-
-        textBox.deleteText();
-
-        JButtonFixture button = frameFixture.button(OTHER_COMPONENT_NAME);
-        button.focus();
-
-        assertEquals(LABEL, textBox.text());
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void verifySearchTextTypedIsReturned() {
-        frameFixture.show();
-
-        final String SEARCH_TEXT = "test";
-        JTextComponentFixture textBox = frameFixture.textBox(SearchFieldView.VIEW_NAME);
-        textBox.enterText(SEARCH_TEXT);
-        String actual = searchField.getSearchText();
-        assertEquals(SEARCH_TEXT, actual);
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void verifyTextSetIsShown() {
-        frameFixture.show();
-
-        final String SEARCH_TEXT = "test";
-        searchField.setSearchText(SEARCH_TEXT);
-        JTextComponentFixture textBox = frameFixture.textBox(SearchFieldView.VIEW_NAME);
-        String actual = textBox.text();
-        assertEquals(SEARCH_TEXT, actual);
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void verifyListenersAreFiredOnTextEntry() {
-        frameFixture.show();
-
-        final String SEARCH_TEXT = "test";
-        ActionListener<SearchFieldView.SearchAction> listener = mock(ActionListener.class);
-
-        JTextComponentFixture textBox = frameFixture.textBox(SearchFieldView.VIEW_NAME);
-
-        searchField.addActionListener(listener);
-
-        textBox.enterText(SEARCH_TEXT);
-
-        verify(listener, times(SEARCH_TEXT.length())).actionPerformed(
-                new ActionEvent<SearchFieldView.SearchAction>(searchField, SearchFieldView.SearchAction.TEXT_CHANGED));
-
-        textBox.enterText("\n");
-
-        verify(listener).actionPerformed(
-                new ActionEvent<SearchFieldView.SearchAction>(searchField, SearchFieldView.SearchAction.PERFORM_SEARCH));
-
-    }
-
-}
--- a/client/core/src/test/java/com/redhat/thermostat/client/internal/osgi/ApplicationServiceProviderTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +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.internal.osgi;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertSame;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.Future;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-public class ApplicationServiceProviderTest {
-
-    private ApplicationServiceProvider provider;
-
-    @Before
-    public void setUp() {
-        provider = new ApplicationServiceProvider();
-    }
-
-    @After
-    public void tearDown() {
-        provider = null;
-    }
-
-    @Test
-    public void testCache() {
-        provider.getApplicationCache().addAttribute("test", "fluff");
-        assertEquals("fluff", provider.getApplicationCache().getAttribute("test"));
-    }
-
-    @Test
-    public void testApplicationExecutor() throws Exception {
-        assertNotNull(provider.getApplicationExecutor());
-        final String obj = "test";
-        Future<String> future = provider.getApplicationExecutor().submit(new Callable<String>() {
-
-            @Override
-            public String call() throws Exception {
-                return obj;
-            }
-        });
-        String result = future.get();
-        assertSame(result, obj);
-    }
-}
--- a/client/core/src/test/java/com/redhat/thermostat/client/internal/osgi/ThermostatActivatorTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +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.internal.osgi;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.client.core.views.AgentInformationViewProvider;
-import com.redhat.thermostat.client.core.views.ClientConfigViewProvider;
-import com.redhat.thermostat.client.core.views.HostCpuViewProvider;
-import com.redhat.thermostat.client.core.views.HostInformationViewProvider;
-import com.redhat.thermostat.client.core.views.HostMemoryViewProvider;
-import com.redhat.thermostat.client.core.views.HostOverviewViewProvider;
-import com.redhat.thermostat.client.core.views.SummaryViewProvider;
-import com.redhat.thermostat.client.core.views.VmCpuViewProvider;
-import com.redhat.thermostat.client.core.views.VmGcViewProvider;
-import com.redhat.thermostat.client.core.views.VmInformationViewProvider;
-import com.redhat.thermostat.client.core.views.VmOverviewViewProvider;
-import com.redhat.thermostat.client.internal.HostIconDecorator;
-import com.redhat.thermostat.client.osgi.service.HostDecorator;
-import com.redhat.thermostat.client.swing.SwingAgentInformationViewProvider;
-import com.redhat.thermostat.client.swing.SwingClientConfigurationViewProvider;
-import com.redhat.thermostat.client.swing.SwingHostCpuViewProvider;
-import com.redhat.thermostat.client.swing.SwingHostInformationViewProvider;
-import com.redhat.thermostat.client.swing.SwingHostMemoryViewProvider;
-import com.redhat.thermostat.client.swing.SwingHostOverviewViewProvider;
-import com.redhat.thermostat.client.swing.SwingSummaryViewProvider;
-import com.redhat.thermostat.client.swing.SwingVmCpuViewProvider;
-import com.redhat.thermostat.client.swing.SwingVmGcViewProvider;
-import com.redhat.thermostat.client.swing.SwingVmInformationViewProvider;
-import com.redhat.thermostat.client.swing.SwingVmOverviewViewProvider;
-import com.redhat.thermostat.test.StubBundleContext;
-
-public class ThermostatActivatorTest {
-
-    @Test
-    public void verifyAllExpectedServicesAreRegistered() throws Exception {
-        StubBundleContext ctx = new StubBundleContext();
-
-        ThermostatActivator activator = new ThermostatActivator();
-
-        activator.start(ctx);
-
-        assertTrue(ctx.isServiceRegistered(HostDecorator.class.getName(), HostIconDecorator.class));
-        assertTrue(ctx.isServiceRegistered(SummaryViewProvider.class.getName(), SwingSummaryViewProvider.class));
-        assertTrue(ctx.isServiceRegistered(HostInformationViewProvider.class.getName(), SwingHostInformationViewProvider.class));
-        assertTrue(ctx.isServiceRegistered(HostMemoryViewProvider.class.getName(), SwingHostMemoryViewProvider.class));
-        assertTrue(ctx.isServiceRegistered(HostCpuViewProvider.class.getName(), SwingHostCpuViewProvider.class));
-        assertTrue(ctx.isServiceRegistered(HostOverviewViewProvider.class.getName(), SwingHostOverviewViewProvider.class));
-        assertTrue(ctx.isServiceRegistered(VmInformationViewProvider.class.getName(), SwingVmInformationViewProvider.class));
-        assertTrue(ctx.isServiceRegistered(VmCpuViewProvider.class.getName(), SwingVmCpuViewProvider.class));
-        assertTrue(ctx.isServiceRegistered(VmGcViewProvider.class.getName(), SwingVmGcViewProvider.class));
-        assertTrue(ctx.isServiceRegistered(VmOverviewViewProvider.class.getName(), SwingVmOverviewViewProvider.class));
-        assertTrue(ctx.isServiceRegistered(AgentInformationViewProvider.class.getName(), SwingAgentInformationViewProvider.class));
-        assertTrue(ctx.isServiceRegistered(ClientConfigViewProvider.class.getName(), SwingClientConfigurationViewProvider.class));
-        
-        assertEquals(12, ctx.getAllServices().size());
-    }
-}
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/AgentInformationDisplayFrameTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,263 +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.ui;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import java.util.HashMap;
-import java.util.Map;
-
-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.edt.GuiTask;
-import org.fest.swing.fixture.FrameFixture;
-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.experimental.categories.Category;
-import org.junit.runner.RunWith;
-
-import com.redhat.thermostat.client.core.views.AgentInformationDisplayView;
-import com.redhat.thermostat.client.core.views.AgentInformationDisplayView.ConfigurationAction;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-
-@RunWith(CacioFESTRunner.class)
-public class AgentInformationDisplayFrameTest {
-
-    private AgentInformationDisplayFrame agentConfigFrame;
-    private FrameFixture fixture;
-    private ActionListener<AgentInformationDisplayView.ConfigurationAction> l;
-
-    @BeforeClass
-    public static void setUpOnce() {
-        FailOnThreadViolationRepaintManager.install();
-    }
-
-    @Before
-    public void setUp() {
-        agentConfigFrame = GuiActionRunner.execute(new GuiQuery<AgentInformationDisplayFrame>() {
-
-            @Override
-            protected AgentInformationDisplayFrame executeInEDT() throws Throwable {
-                return new AgentInformationDisplayFrame();
-            }
-        });
-
-        @SuppressWarnings("unchecked")
-        ActionListener<AgentInformationDisplayView.ConfigurationAction> listener = mock(ActionListener.class);
-        l = listener;
-        agentConfigFrame.addConfigurationListener(l);
-
-        fixture = new FrameFixture(agentConfigFrame.getFrame());
-    }
-
-    @After
-    public void tearDown() {
-        GuiActionRunner.execute(new GuiTask() {
-            @Override
-            protected void executeInEDT() throws Throwable {
-                agentConfigFrame.hideDialog();
-            }
-        });
-
-        fixture.requireNotVisible();
-        agentConfigFrame.removeConfigurationListener(l);
-
-        fixture.cleanUp();
-        fixture = null;
-    }
-
-    @Category(GUITest.class)
-    @GUITest
-    @Test
-    public void testWindowClose() {
-        fixture.show();
-
-        fixture.close();
-
-        verify(l).actionPerformed(eq(new ActionEvent<>(agentConfigFrame, AgentInformationDisplayView.ConfigurationAction.CLOSE)));
-    }
-
-    @Category(GUITest.class)
-    @GUITest
-    @Test
-    public void testClickOnCloseButton() {
-        fixture.show();
-
-        fixture.button("close").click();
-
-        fixture.robot.waitForIdle();
-
-        verify(l).actionPerformed(eq(new ActionEvent<>(agentConfigFrame, AgentInformationDisplayView.ConfigurationAction.CLOSE)));
-    }
-
-    @Category(GUITest.class)
-    @GUITest
-    @Test
-    public void testAddingAgentWorks() {
-        fixture.show();
-        JListFixture list = fixture.list("agentList");
-        assertArrayEquals(new String[0], list.contents());
-
-        agentConfigFrame.addAgent("test-agent");
-
-        assertArrayEquals(new String[] { "test-agent" }, list.contents());
-    }
-
-    @Category(GUITest.class)
-    @GUITest
-    @Test
-    public void testSelectingAgentWorks() {
-        fixture.show();
-        agentConfigFrame.addAgent("testAgent");
-        JListFixture list = fixture.list("agentList");
-
-        list.selectItem("testAgent");
-
-        verify(l, atLeast(1)).actionPerformed(eq(new ActionEvent<>(agentConfigFrame, AgentInformationDisplayView.ConfigurationAction.SWITCH_AGENT)));
-    }
-
-    @Category(GUITest.class)
-    @GUITest
-    @Test
-    public void testFirstAddedAgentIsAutomaticallySelected() {
-        fixture.show();
-        agentConfigFrame.addAgent("testAgent");
-
-        fixture.robot.waitForIdle();
-
-        verify(l).actionPerformed(eq(new ActionEvent<>(agentConfigFrame, AgentInformationDisplayView.ConfigurationAction.SWITCH_AGENT)));
-    }
-
-    @Category(GUITest.class)
-    @GUITest
-    @Test
-    public void testRemovingAllAgentsWorks() {
-        fixture.show();
-        agentConfigFrame.addAgent("test-agent");
-        JListFixture list = fixture.list("agentList");
-
-        agentConfigFrame.clearAllAgents();
-
-        assertArrayEquals(new String[0], list.contents());
-    }
-
-    @Category(GUITest.class)
-    @GUITest
-    @Test
-    public void testInitialInformation() {
-        fixture.show();
-
-        String EMPTY_TEXT = "---";
-
-        assertEquals(EMPTY_TEXT, fixture.textBox("agentName").text());
-        assertEquals(EMPTY_TEXT, fixture.textBox("agentId").text());
-        assertEquals(EMPTY_TEXT, fixture.textBox("commandAddress").text());
-        assertEquals(EMPTY_TEXT, fixture.textBox("startTime").text());
-        assertEquals(EMPTY_TEXT, fixture.textBox("stopTime").text());
-        assertEquals(EMPTY_TEXT, fixture.textBox("backendDescription").text());
-
-    }
-
-    @Category(GUITest.class)
-    @GUITest
-    @Test
-    public void testUpdatingAgentInformationWorks() {
-
-        final String AGENT_NAME = "the-agent-name";
-        final String AGENT_ID = "the-agent-id";
-        final String COMMAND_ADDRESS = "agent-command-channel-address";
-        final String START_TIME = "some-start-time";
-        final String STOP_TIME = "a-certain-stop-time";
-
-        agentConfigFrame.setSelectedAgentName(AGENT_NAME);
-        agentConfigFrame.setSelectedAgentId(AGENT_ID);
-        agentConfigFrame.setSelectedAgentCommandAddress(COMMAND_ADDRESS);
-        agentConfigFrame.setSelectedAgentStartTime(START_TIME);
-        agentConfigFrame.setSelectedAgentStopTime(STOP_TIME);
-
-        fixture.show();
-
-        assertEquals(AGENT_NAME, fixture.textBox("agentName").text());
-        assertEquals(AGENT_ID, fixture.textBox("agentId").text());
-        assertEquals(COMMAND_ADDRESS, fixture.textBox("commandAddress").text());
-        assertEquals(START_TIME, fixture.textBox("startTime").text());
-        assertEquals(STOP_TIME, fixture.textBox("stopTime").text());
-    }
-
-    @Category(GUITest.class)
-    @GUITest
-    @Test
-    public void testBackendDescriptionIsQueriedAndDisplayed() {
-        final String BACKEND_NAME = "foo";
-        final String BACKEND_STATUS = "bar";
-        final String BACKEND_DESCRIPTION = "baz";
-
-        Map<String, String> statusMap = new HashMap<>();
-        statusMap.put(BACKEND_NAME, BACKEND_STATUS);
-
-        fixture.show();
-
-        agentConfigFrame.setSelectedAgentBackendStatus(statusMap);
-
-        assertEquals(1, fixture.table("backends").rowCount());
-
-        String[] rowContents = fixture.table("backends").contents()[0];
-        assertArrayEquals(new String[] { BACKEND_NAME, BACKEND_STATUS }, rowContents);
-
-        fixture.table("backends").selectRows(0);
-
-        verify(l).actionPerformed(new ActionEvent<ConfigurationAction>(agentConfigFrame, ConfigurationAction.SHOW_BACKEND_DESCRIPTION));
-
-        agentConfigFrame.setSelectedAgentBackendDescription(BACKEND_DESCRIPTION);
-
-        assertEquals(BACKEND_DESCRIPTION, fixture.textBox("backendDescription").text());
-    }
-
-}
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/ClientConfigurationSwingTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,196 +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.ui;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import javax.swing.JCheckBox;
-import javax.swing.UIManager;
-
-import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
-
-import org.fest.swing.annotation.GUITest;
-import org.fest.swing.core.matcher.JButtonMatcher;
-import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
-import org.fest.swing.edt.GuiActionRunner;
-import org.fest.swing.edt.GuiQuery;
-import org.fest.swing.fixture.DialogFixture;
-import org.fest.swing.fixture.JButtonFixture;
-import org.fest.swing.fixture.JCheckBoxFixture;
-import org.fest.swing.fixture.JTextComponentFixture;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.runner.RunWith;
-
-import com.redhat.thermostat.client.core.views.ClientConfigurationView;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.test.Bug;
-
-@RunWith(CacioFESTRunner.class)
-public class ClientConfigurationSwingTest {
-    
-    private ClientConfigurationSwing frame;
-    private DialogFixture frameFixture;
-    private ActionListener<ClientConfigurationView.Action> l;
-
-    @BeforeClass
-    public static void setUpOnce() {
-        FailOnThreadViolationRepaintManager.install();
-    }
-
-    @SuppressWarnings("unchecked") // ActionListener
-    @Before
-    public void setUp() {
-        
-        frame = GuiActionRunner.execute(new GuiQuery<ClientConfigurationSwing>() {
-
-            @Override
-            protected ClientConfigurationSwing executeInEDT() throws Throwable {
-                return new ClientConfigurationSwing();
-            }
-        });
-        l = mock(ActionListener.class);
-        frame.addListener(l);
-        frame.showDialog();
-        assertNotNull(frame.getDialog());
-        frameFixture = new DialogFixture(frame.getDialog());
-
-    }
-
-    @After
-    public void tearDown() {
-        frame.hideDialog();
-
-        frameFixture.cleanUp();
-        frame.removeListener(l);
-        frame = null;
-        l = null;
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void testConnectionUrlText() {
-
-        JTextComponentFixture textBox = frameFixture.textBox("connectionUrl");
-        textBox.enterText("foobar");
-
-        assertEquals("foobar", frame.getConnectionUrl());
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void testPasswordText() {
-
-        JTextComponentFixture textBox = frameFixture.textBox("password");
-        textBox.enterText("foobar");
-
-        assertEquals("foobar", frame.getPassword());
-    }
-    
-    @Category(GUITest.class)
-    @Test
-    public void testUsernameText() {
-
-        JTextComponentFixture textBox = frameFixture.textBox("username");
-        textBox.enterText("foobar");
-
-        assertEquals("foobar", frame.getUserName());
-    }
-    
-    @Category(GUITest.class)
-    @Test
-    public void testSaveEntitlements() {
-
-        JCheckBoxFixture saveBox = frameFixture.checkBox("saveEntitlements");
-        saveBox.requireEnabled();
-        saveBox.requireNotSelected();
-
-        saveBox.click();
-        assertEquals(true, frame.getSaveEntitlements());
-        
-        saveBox.click();
-        assertEquals(false, frame.getSaveEntitlements());
-    }
-    
-    @Category(GUITest.class)
-    @Test
-    public void testOkayButton() {
-        JButtonFixture button = frameFixture.button(JButtonMatcher.withText("OK"));
-        button.click();
-
-        verify(l).actionPerformed(eq(new ActionEvent<>(frame, ClientConfigurationView.Action.CLOSE_ACCEPT)));
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void testCancelButton() {
-        JButtonFixture button = frameFixture.button(JButtonMatcher.withText(UIManager.getString("OptionPane.cancelButtonText")));
-        button.click();
-
-        verify(l).actionPerformed(eq(new ActionEvent<>(frame, ClientConfigurationView.Action.CLOSE_CANCEL)));
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void testCloseWindow() {
-        frameFixture.close();
-
-        verify(l).actionPerformed(eq(new ActionEvent<>(frame, ClientConfigurationView.Action.CLOSE_CANCEL)));
-    }
-
-    @Bug(id="1030",
-         summary="Buttons in client preferences dialog should have the same size",
-         url="http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=1030")
-    @Category(GUITest.class)
-    @Test
-    public void testButtonsSameSize() {
-        JButtonFixture cancel = frameFixture.button(JButtonMatcher.withText(UIManager.getString("OptionPane.cancelButtonText")));
-        JButtonFixture ok = frameFixture.button(JButtonMatcher.withText("OK"));
-
-        assertEquals(cancel.target.getSize(), ok.target.getSize());
-
-        frameFixture.close();
-    }
-}
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/HostInformationPanelTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.ui;
-
-import java.lang.reflect.InvocationTargetException;
-
-import javax.swing.JFrame;
-import javax.swing.JTabbedPane;
-
-import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
-import org.fest.swing.edt.GuiActionRunner;
-import org.fest.swing.edt.GuiQuery;
-import org.fest.swing.edt.GuiTask;
-import org.fest.swing.fixture.FrameFixture;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import com.redhat.thermostat.client.core.views.BasicView;
-
-public class HostInformationPanelTest {
-
-    private HostInformationPanel panel;
-    private JFrame frame;
-    private FrameFixture window;
-
-    @BeforeClass
-    public static void setUpOnce() {
-        FailOnThreadViolationRepaintManager.install();
-    }
-
-    @Before
-    public void setUp() {
-        panel = createHostInfoPanel();
-
-        frame = GuiActionRunner.execute(new GuiQuery<JFrame>() {
-            @Override
-            protected JFrame executeInEDT() throws Throwable {
-                JFrame jFrame = new JFrame();
-                panel.getUiComponent().setName("panel");
-                jFrame.add(panel.getUiComponent());
-                return jFrame;
-            }
-        });
-
-        window = new FrameFixture(frame);
-        window.show();
-    }
-
-    @After
-    public void tearDown() {
-        GuiActionRunner.execute(new GuiTask() {
-            @Override
-            protected void executeInEDT() throws Throwable {
-                frame.dispose();
-            }
-        });
-        window.cleanUp();
-    }
-    
-    private HostInformationPanel createHostInfoPanel() {
-        return GuiActionRunner.execute(new GuiQuery<HostInformationPanel>() {
-            @Override
-            protected HostInformationPanel executeInEDT() throws Throwable {
-                return new HostInformationPanel();
-            }
-        });
-    }
-
-    @Test
-    public void testAddTwice() throws InvocationTargetException, InterruptedException {
-        BasicView mock1 = createHostInfoPanel();
-
-        panel.addChildView("foo1", mock1);
-
-        // The panel in test has no views added so the matcher with a tab count > 0 works
-        // in order to select the right panel.
-        window.panel("panel").tabbedPane(new TabbedPaneMatcher(JTabbedPane.class)).requireTabTitles("foo1");
-
-        BasicView mock2 = createHostInfoPanel();
-        panel.addChildView("foo2", mock2);
-
-        window.panel("panel").tabbedPane(new TabbedPaneMatcher(JTabbedPane.class)).requireTabTitles("foo1", "foo2");
-    }
-
-    @Test
-    public void testAddRemove() throws InvocationTargetException, InterruptedException {
-        BasicView test1 = createHostInfoPanel();
-        BasicView test2 = createHostInfoPanel();
-
-        panel.addChildView("test1", test1);
-        panel.addChildView("test2", test2);
-
-        // The panel in test has no views added so the matcher with a tab count > 0 works
-        // in order to select the right panel.
-        window.panel("panel").tabbedPane(new TabbedPaneMatcher(JTabbedPane.class)).requireTabTitles("test1", "test2");
-
-        panel.removeChildView("test1");
-
-        window.panel("panel").tabbedPane(new TabbedPaneMatcher(JTabbedPane.class)).requireTabTitles("test2");
-    }
-}
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/IconDescriptorTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +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.ui;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-import org.junit.Test;
-
-public class IconDescriptorTest {
-
-    @Test
-    public void test() throws IOException {
-        ClassLoader classLoader = getClass().getClassLoader();
-        String resource = IconResource.JAVA_APPLICATION.getPath();
-        IconDescriptor descriptor = IconDescriptor.createFromClassloader(classLoader, resource);
-        ByteBuffer buffer = descriptor.getData();
-        
-        assertEquals(3512, buffer.capacity());
-        
-        byte[] data = buffer.array();
-        
-        // the first four bytes should be .PNG
-        int current = ((int) data[0]) & 0xFF;
-        assertEquals(0x89, current);
-        
-        current = ((int) data[1]) & 0xFF;
-        assertEquals(0x50, current);
-        
-        current = ((int) data[2]) & 0xFF;
-        assertEquals(0x4E, current);
-        
-        current = ((int) data[3]) & 0xFF;
-        assertEquals(0x47, current);
-        
-        // check IHDR chunk
-        current = ((int) data[12]) & 0xFF;
-        assertEquals(0x49, current);
-        
-        current = ((int) data[12]) & 0xFF;
-        assertEquals(0x49, current);
-        
-        current = ((int) data[13]) & 0xFF;
-        assertEquals(0x48, current);
-        
-        current = ((int) data[14]) & 0xFF;
-        assertEquals(0x44, current);
-        
-        current = ((int) data[15]) & 0xFF;
-        assertEquals(0x52, current);
-        
-        // get width and height, 4 bytes each, the icon is 16x16
-        current = ((int) data[16]) << 24 | ((int) data[17]) << 16 | ((int) data[18]) << 8 | (((int) data[19]) & 0xFF);
-        assertEquals(16, current);
-        
-        current = ((int) data[20]) << 24 | ((int) data[21]) << 16 | ((int) data[22]) << 8 | (((int) data[23]) & 0xFF);
-        assertEquals(16, current);
-    }
-    
-}
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/MainWindowTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,356 +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.ui;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.isA;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JRadioButtonMenuItem;
-
-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.exception.ComponentLookupException;
-import org.fest.swing.fixture.FrameFixture;
-import org.fest.swing.fixture.JMenuItemFixture;
-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.experimental.categories.Category;
-import org.junit.runner.RunWith;
-
-import com.redhat.thermostat.client.core.HostFilter;
-import com.redhat.thermostat.client.core.VmFilter;
-import com.redhat.thermostat.client.internal.MainView;
-import com.redhat.thermostat.client.osgi.service.HostDecorator;
-import com.redhat.thermostat.client.osgi.service.MenuAction;
-import com.redhat.thermostat.client.osgi.service.VmDecorator;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.HostsVMsLoader;
-import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.common.dao.Ref;
-
-@RunWith(CacioFESTRunner.class)
-public class MainWindowTest {
-
-    private FrameFixture frameFixture;
-    private MainWindow window;
-    private ActionListener<MainView.Action> l;
-
-    @BeforeClass
-    public static void setUpOnce() {
-        FailOnThreadViolationRepaintManager.install();
-    }
-
-    @SuppressWarnings("unchecked") // mock(ActionListener.class)
-    @Before
-    public void setUp() {
-
-        GuiActionRunner.execute(new GuiTask() {
-            
-            @Override
-            protected void executeInEDT() throws Throwable {
-                window = new MainWindow();
-                l = mock(ActionListener.class);
-                window.addActionListener(l);
-            }
-        });
-
-        frameFixture = new FrameFixture(window);
-    }
-
-    @After
-    public void tearDown() {
-        frameFixture.cleanUp();
-        frameFixture = null;
-        window = null;
-        l = null;
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void testHostVmSelectionChangedSupport() {
-        frameFixture.show();
-        JTreeFixture hostVMTree = frameFixture.tree("agentVmTree");
-        hostVMTree.selectRows(0);
-
-        verify(l).actionPerformed(new ActionEvent<MainView.Action>(window, MainView.Action.HOST_VM_SELECTION_CHANGED));
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void testHostVmDecoratorsAdded() throws InterruptedException {
-        
-        List<HostDecorator> decorators = new ArrayList<>();
-        HostDecorator refDecorator = mock(HostDecorator.class);
-        final Decorator decorator = mock(Decorator.class);
-        when(decorator.getLabel(anyString())).thenReturn("fluff");
-        
-        when(refDecorator.getDecorator()).thenReturn(decorator);
-        
-        HostFilter filter = mock(HostFilter.class);
-        when(filter.matches(isA(HostRef.class))).thenReturn(false).thenReturn(true);
-
-        when(refDecorator.getFilter()).thenReturn(filter);
-        
-        decorators.add(refDecorator);
-        
-        HostsVMsLoader hostsVMsLoader = mock(HostsVMsLoader.class);
-        Collection<HostRef> expectedHosts = new ArrayList<>();
-        expectedHosts.add(new HostRef("123", "fluffhost1"));
-        expectedHosts.add(new HostRef("456", "fluffhost2"));
-        
-        when(hostsVMsLoader.getHosts()).thenReturn(expectedHosts);
-        
-        window.updateTree(null, null, decorators, null, hostsVMsLoader);
-
-        Thread.sleep(50);
-        
-        frameFixture.show();
-        frameFixture.requireVisible();
-        
-        verify(decorator, times(0)).getLabel("fluffhost1");
-        verify(decorator, atLeastOnce()).getLabel("fluffhost2");
-    }
-    
-    @Category(GUITest.class)
-    @Test
-    public void testHostVMTreeFilterPropertySupport() {
-        String SEARCH_TEXT = "test";
-        frameFixture.show();
-        JTextComponentFixture hostVMTreeFilterField = frameFixture.textBox(SearchFieldView.VIEW_NAME);
-        hostVMTreeFilterField.enterText(SEARCH_TEXT);
-
-        verify(l, times(SEARCH_TEXT.length())).actionPerformed(new ActionEvent<MainView.Action>(window, MainView.Action.HOST_VM_TREE_FILTER));
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void verifyThatCloseFiresShutdownEvent() {
-
-        frameFixture.show();
-
-        frameFixture.close();
-        frameFixture.requireNotVisible();
-        verify(l).actionPerformed(new ActionEvent<MainView.Action>(window, MainView.Action.SHUTDOWN));
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void verifyShowMainWindowShowsWindow() {
-        window.showMainWindow();
-        frameFixture.requireVisible();
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void verifyHideMainWindowHidesWindow() {
-        GuiActionRunner.execute(new GuiTask() {
-            @Override
-            protected void executeInEDT() throws Throwable {
-                window.showMainWindow();
-            }
-        });
-        frameFixture.requireVisible();
-        GuiActionRunner.execute(new GuiTask() {
-            @Override
-            protected void executeInEDT() throws Throwable {
-                window.hideMainWindow();
-            }
-        });
-        frameFixture.requireNotVisible();
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void verifyThatClientPreferencesMenuItemTriggersEvent() {
-        frameFixture.show();
-        JMenuItemFixture menuItem = frameFixture.menuItem("showClientConfig");
-        menuItem.click();
-        frameFixture.close();
-        frameFixture.requireNotVisible();
-
-        verify(l).actionPerformed(new ActionEvent<MainView.Action>(window, MainView.Action.SHOW_CLIENT_CONFIG));
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void verifyThatAgentPreferencesMenuItemTriggersEvent() {
-        frameFixture.show();
-        JMenuItemFixture menuItem = frameFixture.menuItem("showAgentConfig");
-        menuItem.click();
-        frameFixture.close();
-        frameFixture.requireNotVisible();
-
-        verify(l).actionPerformed(new ActionEvent<MainView.Action>(window, MainView.Action.SHOW_AGENT_CONFIG));
-    }
-
-
-    @Category(GUITest.class)
-    @Test
-    public void verifyThatHistorySwitchTriggersEvent() {
-        frameFixture.show();
-        JMenuItemFixture menuItem = frameFixture.menuItem("historyModeSwitch");
-        menuItem.click();
-        frameFixture.close();
-        frameFixture.requireNotVisible();
-
-        verify(l).actionPerformed(new ActionEvent<MainView.Action>(window, MainView.Action.SWITCH_HISTORY_MODE));
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void addRemoveMenu() {
-    	final String PARENT_NAME = "File";
-        final String MENU_NAME = "Test2";
-        MenuAction action = mock(MenuAction.class);
-        when(action.getName()).thenReturn(MENU_NAME);
-        when(action.getPath()).thenReturn(new String[] {PARENT_NAME, MENU_NAME});
-        when(action.getType()).thenReturn(MenuAction.Type.STANDARD);
-
-        JMenuItemFixture menuItem;
-
-        frameFixture.show();
-
-        window.addMenu(action);
-
-        menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
-        assertNotNull(menuItem);
-        menuItem.click();
-
-        verify(action).execute();
-
-        window.removeMenu(action);
-
-        try {
-            menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
-            // should not reach here
-            assertTrue(false);
-        } catch (ComponentLookupException cle) {
-            // expected
-        }
-    }
-    
-    @Category(GUITest.class)
-    @Test
-    public void addRadioMenu() {
-    	final String PARENT_NAME = "File";
-        final String MENU_NAME = "Test";
-        MenuAction action = mock(MenuAction.class);
-        when(action.getName()).thenReturn(MENU_NAME);
-        when(action.getPath()).thenReturn(new String[] {PARENT_NAME, MENU_NAME});
-
-
-        when(action.getType()).thenReturn(MenuAction.Type.RADIO);
-
-        JMenuItemFixture menuItem;
-
-        frameFixture.show();
-
-        window.addMenu(action);
-
-        menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
-        assertNotNull(menuItem);
-
-        assertTrue(menuItem.target instanceof JRadioButtonMenuItem);
-    }
-    
-    @Category(GUITest.class)
-    @Test
-    public void addCheckBoxMenu() {
-    	final String PARENT_NAME = "File";
-        final String MENU_NAME = "Test";
-        MenuAction action = mock(MenuAction.class);
-        when(action.getName()).thenReturn(MENU_NAME);
-        when(action.getType()).thenReturn(MenuAction.Type.CHECK);
-        when(action.getPath()).thenReturn(new String[] {PARENT_NAME, MENU_NAME});
-
-
-        JMenuItemFixture menuItem;
-
-        frameFixture.show();
-
-        window.addMenu(action);
-
-        menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
-        assertNotNull(menuItem);
-
-        assertTrue(menuItem.target instanceof JCheckBoxMenuItem);
-    }
-    
-    @Category(GUITest.class)
-    @Test
-    public void testGetHostVMTreeFilter() {
-        frameFixture.show();
-        JTextComponentFixture hostVMTreeFilterField = frameFixture.textBox(SearchFieldView.VIEW_NAME);
-        hostVMTreeFilterField.enterText("test");
-        String actual = window.getHostVmTreeFilterText();
-        assertEquals("test", actual);
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void testGetSelectedHostOrVm() {
-        frameFixture.show();
-        JTreeFixture hostVMTree = frameFixture.tree("agentVmTree");
-        hostVMTree.selectRow(0);
-
-        assertEquals(null, window.getSelectedHostOrVm());
-    }
-
-}
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/MenuHelperTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.ui;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JFrame;
-import javax.swing.JMenu;
-import javax.swing.JMenuBar;
-import javax.swing.JRadioButtonMenuItem;
-
-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.exception.ComponentLookupException;
-import org.fest.swing.fixture.FrameFixture;
-import org.fest.swing.fixture.JMenuItemFixture;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.runner.RunWith;
-
-import com.redhat.thermostat.client.osgi.service.MenuAction;
-
-@RunWith(CacioFESTRunner.class)
-public class MenuHelperTest {
-
-    private FrameFixture frameFixture;
-    private JFrame window;
-    private MenuHelper menu;
-
-    @BeforeClass
-    public static void setUpOnce() {
-        FailOnThreadViolationRepaintManager.install();
-    }
-
-    @Before
-    public void setUp() {
-        GuiActionRunner.execute(new GuiTask() {
-            @Override
-            protected void executeInEDT() throws Throwable {
-                window = new JFrame();
-                JMenuBar menuBar = new JMenuBar();
-                window.setJMenuBar(menuBar);
-                JMenu fileMenu = new JMenu("File");
-                fileMenu.setName("File");
-                menuBar.add(fileMenu);
-                menu = new MenuHelper(menuBar);
-                window.pack();
-            }
-        });
-
-        frameFixture = new FrameFixture(window);
-    }
-
-    @After
-    public void tearDown() {
-        frameFixture.cleanUp();
-        frameFixture = null;
-        window = null;
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void addRemoveWithNewTopLevelMenu() {
-        final String PARENT_NAME = "Test1";
-        final String MENU_NAME = "Test2";
-        MenuAction action = mock(MenuAction.class);
-        when(action.getName()).thenReturn(MENU_NAME);
-        when(action.getPath()).thenReturn(new String[] { PARENT_NAME, MENU_NAME });
-        when(action.getType()).thenReturn(MenuAction.Type.STANDARD);
-
-        JMenuItemFixture menuItem;
-
-        frameFixture.show();
-
-        menu.addMenuAction(action);
-
-        menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
-        assertNotNull(menuItem);
-
-        menu.removeMenuAction(action);
-
-        try {
-            menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
-            // should not reach here
-            assertTrue(false);
-        } catch (ComponentLookupException cle) {
-            // expected
-        }
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void addRemoveToExistingMenu() {
-        final String PARENT_NAME = "File";
-        final String MENU_NAME = "Test2";
-        MenuAction action = mock(MenuAction.class);
-        when(action.getName()).thenReturn(MENU_NAME);
-        when(action.getPath()).thenReturn(new String[] { PARENT_NAME, MENU_NAME });
-        when(action.getType()).thenReturn(MenuAction.Type.STANDARD);
-
-        JMenuItemFixture menuItem;
-
-        frameFixture.show();
-
-        assertNotNull(frameFixture.menuItem("File"));
-
-        menu.addMenuAction(action);
-
-        menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
-        assertNotNull(menuItem);
-
-        menu.removeMenuAction(action);
-
-        try {
-            menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
-            // should not reach here
-            assertTrue(false);
-        } catch (ComponentLookupException cle) {
-            // expected
-        }
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void addRemoveHighlyNextedMenu() {
-        final String[] path = new String[] { "View", "Filter", "Virtual Machine", "Show Only Running" };
-        MenuAction action = mock(MenuAction.class);
-        when(action.getName()).thenReturn(path[path.length - 1]);
-        when(action.getPath()).thenReturn(path);
-        when(action.getType()).thenReturn(MenuAction.Type.STANDARD);
-
-        JMenuItemFixture menuItem;
-
-        frameFixture.show();
-
-        menu.addMenuAction(action);
-
-        menuItem = frameFixture.menuItemWithPath(path);
-        assertNotNull(menuItem);
-
-        menu.removeMenuAction(action);
-
-        try {
-            menuItem = frameFixture.menuItemWithPath(path);
-            // should not reach here
-            assertTrue(false);
-        } catch (ComponentLookupException cle) {
-            // expected
-        }
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void addRadioMenu() {
-        final String PARENT_NAME = "File";
-        final String MENU_NAME = "Test";
-        MenuAction action = mock(MenuAction.class);
-        when(action.getName()).thenReturn(MENU_NAME);
-        when(action.getPath()).thenReturn(new String[] { PARENT_NAME, MENU_NAME });
-        when(action.getType()).thenReturn(MenuAction.Type.RADIO);
-
-        JMenuItemFixture menuItem;
-
-        frameFixture.show();
-
-        menu.addMenuAction(action);
-
-        menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
-        assertNotNull(menuItem);
-
-        assertTrue(menuItem.target instanceof JRadioButtonMenuItem);
-    }
-
-    @Category(GUITest.class)
-    @Test
-    public void addCheckBoxMenu() {
-        final String PARENT_NAME = "File";
-        final String MENU_NAME = "Test";
-        MenuAction action = mock(MenuAction.class);
-        when(action.getName()).thenReturn(MENU_NAME);
-        when(action.getType()).thenReturn(MenuAction.Type.CHECK);
-        when(action.getPath()).thenReturn(new String[] { PARENT_NAME, MENU_NAME });
-
-        JMenuItemFixture menuItem;
-
-        frameFixture.show();
-
-        menu.addMenuAction(action);
-
-        menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
-        assertNotNull(menuItem);
-
-        assertTrue(menuItem.target instanceof JCheckBoxMenuItem);
-    }
-
-}
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/TabbedPaneMatcher.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-package com.redhat.thermostat.client.ui;
-
-import javax.swing.JTabbedPane;
-
-import org.fest.swing.core.GenericTypeMatcher;
-
-public class TabbedPaneMatcher extends GenericTypeMatcher<JTabbedPane> {
-
-    public TabbedPaneMatcher(Class<JTabbedPane> supportedType) {
-        super(supportedType);
-    }
-
-    @Override
-    protected boolean isMatching(JTabbedPane tab) {
-        return tab.getTabCount() > 0;
-    }
-
-}
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/UIResourcesTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,141 +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.ui;
-
-import java.awt.Color;
-import java.awt.Font;
-
-import javax.swing.LookAndFeel;
-import javax.swing.UIDefaults;
-import javax.swing.UIManager;
-import javax.swing.plaf.basic.BasicLookAndFeel;
-
-import junit.framework.Assert;
-
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import com.redhat.thermostat.test.Bug;
-
-@Bug(id="976",
-     summary="About dialog creashes with GTK look and feel",
-     url="http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=976")
-public class UIResourcesTest {
-   
-    private static LookAndFeel originalLaf;
-    
-    @BeforeClass
-    public static void setUp() throws Exception {
-        final Object [] uiDefaults = new Object[] {
-            "Button.darkShadow", null,
-            "Button.focus", null,
-            "Label.font", null
-        };
-        
-        originalLaf = UIManager.getLookAndFeel();
-        UIManager.setLookAndFeel(new BasicLookAndFeel() {
-            
-            @Override
-            protected void initClassDefaults(UIDefaults table) {
-                super.initClassDefaults(table);
-                table.putDefaults(uiDefaults);
-            }
-            
-            @Override
-            protected void initSystemColorDefaults(UIDefaults table) {
-                super.initSystemColorDefaults(table);
-                table.putDefaults(uiDefaults);
-            }
-            
-            @Override
-            protected void initComponentDefaults(UIDefaults table) {
-                super.initComponentDefaults(table);
-                table.putDefaults(uiDefaults);
-            }
-            
-            @Override
-            public boolean isSupportedLookAndFeel() {
-                return true;
-            }
-            
-            @Override
-            public boolean isNativeLookAndFeel() {
-                return false;
-            }
-            
-            @Override
-            public String getName() {
-                return "fluff";
-            }
-            
-            @Override
-            public String getID() {
-                return "fluff";
-            }
-            
-            @Override
-            public String getDescription() {
-                return "fluff";
-            }
-        });
-    }
-    
-    @Test
-    public void testHyperlinkColor() {
-        Assert.assertEquals(Color.BLUE, UIResources.getInstance().hyperlinkColor());
-    }
-
-    @Test
-    public void testHyperlinkActiveColor() {
-        Assert.assertEquals(Color.BLUE, UIResources.getInstance().hyperlinkActiveColor());
-    }
-
-    @Test
-    public void testStandardFont() {
-        Assert.assertEquals(Font.DIALOG, UIResources.getInstance().standardFont().getName());
-    }
-    
-    @AfterClass
-    public static void tearDown() throws Exception {
-        if (originalLaf != null) {
-            UIManager.setLookAndFeel(originalLaf);
-        } else {
-            UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,136 @@
+<?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.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>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapDumpController.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,271 @@
+/*
+ * 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.client.osgi.service.ApplicationService;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.NotImplementedException;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.Timer.SchedulingType;
+import com.redhat.thermostat.common.appctx.ApplicationContext;
+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.model.HeapInfo;
+import com.redhat.thermostat.common.model.VmMemoryStat;
+import com.redhat.thermostat.common.model.VmMemoryStat.Generation;
+import com.redhat.thermostat.common.model.VmMemoryStat.Space;
+import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
+
+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 = ApplicationContext.getInstance().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();
+                        }
+                    });
+                    
+                    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();
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapDumpDetailsView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapDumpDetailsViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.heap;
+
+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/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapDumperService.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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.client.osgi.service.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 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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapHistogramView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapHistogramViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.heap;
+
+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/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapObjectUI.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/HeapViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.heap;
+
+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/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/LocaleResources.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,107 @@
+/*
+ * 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,
+
+    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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/ObjectDetailsView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/ObjectDetailsViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.heap;
+
+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/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/ObjectRootsView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/ObjectRootsViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.heap;
+
+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/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/chart/OverviewChart.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/DumpHeapCommand.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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(CommandContext ctx) throws CommandException {
+        HostVMArguments args = new HostVMArguments(ctx.getArguments());
+
+        final Semaphore s = new Semaphore(0);
+        Runnable r = new Runnable() {
+            
+            @Override
+            public void run() {
+                s.release();
+            }
+        };
+        AgentInfoDAO service = serviceProvider.getService(AgentInfoDAO.class);
+        if (service == null) {
+            throw new CommandException("Unable to access agent information");
+        }
+        implementation.execute(service, args.getVM(), r);
+        serviceProvider.ungetService(AgentInfoDAO.class, service);
+
+        try {
+            s.acquire();
+            ctx.getConsole().getOutput().print(translator.localize(LocaleResources.COMMAND_HEAP_DUMP_DONE));
+            ctx.getConsole().getOutput().print("\n");
+        } catch (InterruptedException ex) {
+            // Nothing to do here, just return ASAP.
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/FindObjectsCommand.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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.model.HeapInfo;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+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/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/FindRoot.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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;
+        }
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/FindRootCommand.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommand.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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.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 heapDumpCompleteAction;
+
+        private HeapDumpListener(Runnable heapDumpCompleteAction) {
+            this.heapDumpCompleteAction = heapDumpCompleteAction;
+        }
+
+        @Override
+        public void fireComplete(Request request, Response response) {
+            heapDumpCompleteAction.run();
+        }
+        
+    }
+
+    public void execute(AgentInfoDAO agentInfoDAO, VmRef reference, Runnable heapDumpCompleteAction) {
+
+        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(heapDumpCompleteAction));
+
+        RequestQueue queue = OSGIUtils.getInstance().getService(RequestQueue.class);
+        queue.putRequest(req);
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/HeapNotFoundException.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/HeapPath.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/ListHeapDumpsCommand.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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.model.HeapInfo;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+
+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/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/ObjectCommandHelper.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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.common.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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/ObjectInfoCommand.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/ObjectNotFoundException.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/SaveHeapDumpToFileCommand.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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.model.HeapInfo;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.common.utils.StreamUtils;
+
+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/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/cli/ShowHeapHistogramCommand.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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.model.HeapInfo;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+
+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/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/internal/Activator.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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();
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/internal/HeapDumpDetailsController.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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.client.osgi.service.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;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/internal/Histogram.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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;
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/internal/ObjectDetailsController.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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.client.osgi.service.ApplicationService;
+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.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/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/internal/ObjectRootsController.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/java/com/redhat/thermostat/client/heap/internal/PrintObjectUtils.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/resources/META-INF/services/com.redhat.thermostat.common.cli.Command	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,7 @@
+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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/main/resources/com/redhat/thermostat/client/heap/strings.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,58 @@
+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
+
+
+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 = Memory 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/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/HeapDumpControllerTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,405 @@
+/*
+ * 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.client.osgi.service.ApplicationCache;
+import com.redhat.thermostat.client.osgi.service.ApplicationService;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.TimerFactory;
+import com.redhat.thermostat.common.appctx.ApplicationContext;
+import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
+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.model.HeapInfo;
+import com.redhat.thermostat.common.model.VmMemoryStat;
+import com.redhat.thermostat.common.model.VmMemoryStat.Generation;
+import com.redhat.thermostat.common.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() {
+        ApplicationContextUtil.resetApplicationContext();
+
+        agentDao = mock(AgentInfoDAO.class);
+        heapDao = mock(HeapDAO.class);
+        vmDao = mock(VmMemoryStatDAO.class);
+
+        setUpTimers();
+        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);
+        ApplicationContext.getInstance().setTimerFactory(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);
+        appService = mock(ApplicationService.class);
+        when(appService.getApplicationCache()).thenReturn(cache);
+        VmRef ref = mock(VmRef.class);
+        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;
+        ApplicationContextUtil.resetApplicationContext();
+    }
+
+    @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() {
+        
+        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);
+        
+        appService = mock(ApplicationService.class);
+        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() {
+
+        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);
+        
+        appService = mock(ApplicationService.class);
+        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());
+        heapDumpCompleteAction.getValue().run();
+        verify(view).notifyHeapDumpComplete();
+
+    }
+ 
+    @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/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/HeapDumpDetailsControllerTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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.client.osgi.service.ApplicationService;
+import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
+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() {
+        ApplicationContextUtil.resetApplicationContext();
+
+        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;
+        ApplicationContextUtil.resetApplicationContext();
+    }
+
+    @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/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/LocaleResourcesTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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()));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/ObjectDetailsControllerTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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.client.osgi.service.ApplicationService;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
+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() {
+        ApplicationContextUtil.resetApplicationContext();
+
+        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;
+        ApplicationContextUtil.resetApplicationContext();
+    }
+
+    @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/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/ObjectRootsControllerTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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.After;
+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.appctx.ApplicationContextUtil;
+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() {
+        ApplicationContextUtil.resetApplicationContext();
+
+        // 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();
+    }
+
+    @After
+    public void tearDown() {
+        ApplicationContextUtil.resetApplicationContext();
+    }
+
+
+    @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/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/DumpHeapCommandTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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> arg = ArgumentCaptor.forClass(Runnable.class);
+        doAnswer(new Answer<Void>() {
+
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                arg.getValue().run();
+                return null;
+            }
+        }).when(impl).execute(eq(agentInfoDao), any(VmRef.class), arg.capture());
+
+        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));
+        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());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/FindObjectsCommandTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,225 @@
+/*
+ * 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.model.HeapInfo;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+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());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/FindRootCommandTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,345 @@
+/*
+ * 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.model.HeapInfo;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+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());
+         }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommandTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,138 @@
+/*
+ * 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.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.appctx.ApplicationContextUtil;
+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.model.AgentInformation;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+
+public class HeapDumperCommandTest {
+
+    private AgentInfoDAO agentInfoDao;
+    private HeapDumperCommand cmd;
+    private VmRef vmRef;
+    private RequestQueue reqQueue;
+    private Runnable heapDumpCompleteAction;
+
+    @Before
+    public void setUp() {
+        ApplicationContextUtil.resetApplicationContext();
+
+        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);
+
+    }
+
+    @After
+    public void tearDown() {
+        heapDumpCompleteAction = null;
+        vmRef = null;
+        cmd = null;
+        reqQueue = null;
+        ApplicationContextUtil.resetApplicationContext();
+    }
+
+    @Test
+	public void testExecute() {
+
+        cmd.execute(agentInfoDao, vmRef, heapDumpCompleteAction);
+
+		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();
+    }
+
+    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/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/ListHeapDumpsCommandTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,278 @@
+/*
+ * 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.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
+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.model.HeapInfo;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+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);
+    }
+
+    @Before
+    public void setUp() {
+        ApplicationContextUtil.resetApplicationContext();
+    }
+
+    @After
+    public void tearDown() {
+        ApplicationContextUtil.resetApplicationContext();
+
+    }
+
+    @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/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/ObjectInfoCommandTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,240 @@
+/*
+ * 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.model.HeapInfo;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+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());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/SaveHeapDumpToFileCommandTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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.model.HeapInfo;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+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());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/cli/ShowHeapHistogramCommandTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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.model.HeapInfo;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/core/src/test/java/com/redhat/thermostat/client/heap/internal/ActivatorTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,70 @@
+/*
+ * 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 org.junit.Test;
+
+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;
+
+public class ActivatorTest {
+
+    @Test
+    public void testCommandsRegistered() throws Exception {
+        StubBundleContext ctx = new StubBundleContext();
+        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	Fri Oct 26 13:13:42 2012 +0200
+++ b/client/heapdumper/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -38,116 +38,21 @@
 -->
 <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>
-    <groupId>com.redhat.thermostat</groupId>
     <version>0.5.0-SNAPSHOT</version>
   </parent>
+
   <artifactId>thermostat-client-heapdumper</artifactId>
-  <packaging>bundle</packaging>
+  <packaging>pom</packaging>
+
   <name>Thermostat Client Heap Dumper 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.Activator</Bundle-Activator>
-            <Bundle-SymbolicName>com.redhat.thermostat.client.heapdumper</Bundle-SymbolicName>
-            <Private-Package>
-               com.redhat.thermostat.client.heap,
-               com.redhat.thermostat.client.heap.cli,
-               com.redhat.thermostat.client.heap.swing,
-               com.redhat.thermostat.client.heap.chart
-            </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-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-swing-components</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>
+  <modules>
+    <module>core</module>
+    <module>swing</module>
+  </modules>
 
-    <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/src/main/java/com/redhat/thermostat/client/heap/Activator.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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;
-
-import java.util.Map;
-import java.util.Objects;
-import java.util.ServiceLoader;
-
-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.swing.SwingHeapDumpDetailsViewProvider;
-import com.redhat.thermostat.client.heap.swing.SwingHeapHistogramViewProvider;
-import com.redhat.thermostat.client.heap.swing.SwingHeapViewProvider;
-import com.redhat.thermostat.client.heap.swing.SwingObjectDetailsViewProvider;
-import com.redhat.thermostat.client.heap.swing.SwingObjectRootsViewProvider;
-import com.redhat.thermostat.client.osgi.service.ApplicationService;
-import com.redhat.thermostat.common.MultipleServiceTracker;
-import com.redhat.thermostat.common.MultipleServiceTracker.Action;
-import com.redhat.thermostat.common.cli.Command;
-import com.redhat.thermostat.common.cli.CommandRegistry;
-import com.redhat.thermostat.common.cli.CommandRegistryImpl;
-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 CommandRegistry reg;
-    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();
-
-        reg = new CommandRegistryImpl(context);
-        ServiceLoader<Command> cmds = ServiceLoader.load(Command.class,
-                getClass().getClassLoader());
-        reg.registerCommands(cmds);
-    }
-
-    @Override
-    public void stop(BundleContext context) throws Exception {
-        heapDumperServiceTracker.close();
-        reg.unregisterCommands();
-    }
-    
-    // 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/src/main/java/com/redhat/thermostat/client/heap/HeapDumpController.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,270 +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.osgi.service.ApplicationService;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.NotImplementedException;
-import com.redhat.thermostat.common.Timer;
-import com.redhat.thermostat.common.Timer.SchedulingType;
-import com.redhat.thermostat.common.appctx.ApplicationContext;
-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.model.HeapInfo;
-import com.redhat.thermostat.common.model.VmMemoryStat;
-import com.redhat.thermostat.common.model.VmMemoryStat.Generation;
-import com.redhat.thermostat.common.model.VmMemoryStat.Space;
-import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
-
-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 = ApplicationContext.getInstance().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();
-                        }
-                    });
-                    
-                    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/src/main/java/com/redhat/thermostat/client/heap/HeapDumpDetailsController.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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;
-
-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.osgi.service.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/src/main/java/com/redhat/thermostat/client/heap/HeapDumpDetailsView.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/HeapDumpDetailsViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/HeapDumperService.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +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.client.osgi.service.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 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;
-    }
-}
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapHistogramView.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/HeapHistogramViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/HeapObjectUI.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/HeapView.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.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);
-
-}
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/Histogram.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.heap;
-
-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/src/main/java/com/redhat/thermostat/client/heap/LocaleResources.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +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,
-
-    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/src/main/java/com/redhat/thermostat/client/heap/ObjectDetailsController.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,203 +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.ArrayList;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.List;
-
-import com.redhat.thermostat.client.heap.ObjectDetailsView.ObjectAction;
-import com.redhat.thermostat.client.heap.ObjectDetailsView.ObjectReferenceCallback;
-import com.redhat.thermostat.client.osgi.service.ApplicationService;
-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.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/src/main/java/com/redhat/thermostat/client/heap/ObjectDetailsView.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.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/src/main/java/com/redhat/thermostat/client/heap/ObjectDetailsViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/ObjectRootsController.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,128 +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.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-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/src/main/java/com/redhat/thermostat/client/heap/ObjectRootsView.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/ObjectRootsViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/PrintObjectUtils.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.sun.tools.hat.internal.model.JavaHeapObject;
-
-public class PrintObjectUtils {
-
-    public static String objectToString(JavaHeapObject obj) {
-        return obj.getClazz().getName() + "@" + obj.getIdString();
-    }
-}
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/chart/OverviewChart.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.charts.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/src/main/java/com/redhat/thermostat/client/heap/cli/DumpHeapCommand.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +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(CommandContext ctx) throws CommandException {
-        HostVMArguments args = new HostVMArguments(ctx.getArguments());
-
-        final Semaphore s = new Semaphore(0);
-        Runnable r = new Runnable() {
-            
-            @Override
-            public void run() {
-                s.release();
-            }
-        };
-        AgentInfoDAO service = serviceProvider.getService(AgentInfoDAO.class);
-        if (service == null) {
-            throw new CommandException("Unable to access agent information");
-        }
-        implementation.execute(service, args.getVM(), r);
-        serviceProvider.ungetService(AgentInfoDAO.class, service);
-
-        try {
-            s.acquire();
-            ctx.getConsole().getOutput().print(translator.localize(LocaleResources.COMMAND_HEAP_DUMP_DONE));
-            ctx.getConsole().getOutput().print("\n");
-        } catch (InterruptedException ex) {
-            // Nothing to do here, just return ASAP.
-        }
-    }
-
-}
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/cli/FindObjectsCommand.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.model.HeapInfo;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-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/src/main/java/com/redhat/thermostat/client/heap/cli/FindRoot.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/cli/FindRootCommand.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.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/src/main/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommand.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +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.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 heapDumpCompleteAction;
-
-        private HeapDumpListener(Runnable heapDumpCompleteAction) {
-            this.heapDumpCompleteAction = heapDumpCompleteAction;
-        }
-
-        @Override
-        public void fireComplete(Request request, Response response) {
-            heapDumpCompleteAction.run();
-        }
-        
-    }
-
-    public void execute(AgentInfoDAO agentInfoDAO, VmRef reference, Runnable heapDumpCompleteAction) {
-
-        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(heapDumpCompleteAction));
-
-        RequestQueue queue = OSGIUtils.getInstance().getService(RequestQueue.class);
-        queue.putRequest(req);
-
-    }
-
-}
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/cli/HeapNotFoundException.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/cli/HeapPath.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/cli/ListHeapDumpsCommand.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.model.HeapInfo;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-
-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/src/main/java/com/redhat/thermostat/client/heap/cli/ObjectCommandHelper.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.common.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/src/main/java/com/redhat/thermostat/client/heap/cli/ObjectInfoCommand.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.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/src/main/java/com/redhat/thermostat/client/heap/cli/ObjectNotFoundException.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/cli/SaveHeapDumpToFileCommand.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.model.HeapInfo;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.common.utils.StreamUtils;
-
-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/src/main/java/com/redhat/thermostat/client/heap/cli/ShowHeapHistogramCommand.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.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.model.HeapInfo;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-
-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/src/main/java/com/redhat/thermostat/client/heap/swing/HeapDetailsSwing.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.ui.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/src/main/java/com/redhat/thermostat/client/heap/swing/HeapPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/swing/HeapSwingView.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,230 +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.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.ui.ComponentVisibleListener;
-import com.redhat.thermostat.client.ui.SwingComponent;
-import com.redhat.thermostat.common.heap.HeapDump;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.swing.HeaderPanel;
-
-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);
-            }
-        });
-    }
-}
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/HistogramPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.ui.SwingComponent;
-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;
-import com.redhat.thermostat.swing.HeaderPanel;
-import com.redhat.thermostat.swing.ThermostatTable;
-import com.redhat.thermostat.swing.ThermostatTableRenderer;
-
-@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/src/main/java/com/redhat/thermostat/client/heap/swing/LazyMutableTreeNode.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/swing/ObjectDetailsPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.heap.HeapObjectUI;
-import com.redhat.thermostat.client.heap.LocaleResources;
-import com.redhat.thermostat.client.heap.ObjectDetailsView;
-import com.redhat.thermostat.client.ui.SearchFieldSwingView;
-import com.redhat.thermostat.client.ui.SearchFieldView.SearchAction;
-import com.redhat.thermostat.client.ui.SwingComponent;
-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.swing.EdtHelper;
-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/src/main/java/com/redhat/thermostat/client/heap/swing/ObjectRootsFrame.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.common.ActionListener;
-import com.redhat.thermostat.common.ActionNotifier;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.swing.EdtHelper;
-
-@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/src/main/java/com/redhat/thermostat/client/heap/swing/StatsPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/swing/SwingHeapDumpDetailsViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/swing/SwingHeapHistogramViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/swing/SwingHeapViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/swing/SwingObjectDetailsViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/java/com/redhat/thermostat/client/heap/swing/SwingObjectRootsViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/resources/META-INF/services/com.redhat.thermostat.common.cli.Command	Fri Oct 26 13:13:42 2012 +0200
+++ /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/src/main/resources/com/redhat/thermostat/client/heap/strings.properties	Fri Oct 26 13:13:42 2012 +0200
+++ /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
-
-
-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 = Memory 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/src/test/java/com/redhat/thermostat/client/heap/HeapDumpControllerTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,405 +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.client.osgi.service.ApplicationCache;
-import com.redhat.thermostat.client.osgi.service.ApplicationService;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.Timer;
-import com.redhat.thermostat.common.TimerFactory;
-import com.redhat.thermostat.common.appctx.ApplicationContext;
-import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
-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.model.HeapInfo;
-import com.redhat.thermostat.common.model.VmMemoryStat;
-import com.redhat.thermostat.common.model.VmMemoryStat.Generation;
-import com.redhat.thermostat.common.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() {
-        ApplicationContextUtil.resetApplicationContext();
-
-        agentDao = mock(AgentInfoDAO.class);
-        heapDao = mock(HeapDAO.class);
-        vmDao = mock(VmMemoryStatDAO.class);
-
-        setUpTimers();
-        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);
-        ApplicationContext.getInstance().setTimerFactory(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);
-        appService = mock(ApplicationService.class);
-        when(appService.getApplicationCache()).thenReturn(cache);
-        VmRef ref = mock(VmRef.class);
-        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;
-        ApplicationContextUtil.resetApplicationContext();
-    }
-
-    @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() {
-        
-        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);
-        
-        appService = mock(ApplicationService.class);
-        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() {
-
-        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);
-        
-        appService = mock(ApplicationService.class);
-        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());
-        heapDumpCompleteAction.getValue().run();
-        verify(view).notifyHeapDumpComplete();
-
-    }
- 
-    @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/src/test/java/com/redhat/thermostat/client/heap/HeapDumpDetailsControllerTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +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.osgi.service.ApplicationService;
-import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
-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() {
-        ApplicationContextUtil.resetApplicationContext();
-
-        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;
-        ApplicationContextUtil.resetApplicationContext();
-    }
-
-    @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/src/test/java/com/redhat/thermostat/client/heap/LocaleResourcesTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.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/src/test/java/com/redhat/thermostat/client/heap/ObjectDetailsControllerTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,288 +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.osgi.service.ApplicationService;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
-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() {
-        ApplicationContextUtil.resetApplicationContext();
-
-        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;
-        ApplicationContextUtil.resetApplicationContext();
-    }
-
-    @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/src/test/java/com/redhat/thermostat/client/heap/ObjectRootsControllerTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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;
-
-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.After;
-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.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
-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() {
-        ApplicationContextUtil.resetApplicationContext();
-
-        // 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();
-    }
-
-    @After
-    public void tearDown() {
-        ApplicationContextUtil.resetApplicationContext();
-    }
-
-
-    @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/src/test/java/com/redhat/thermostat/client/heap/ServicesAvailableActionTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +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.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.Activator.ServicesAvailableAction;
-import com.redhat.thermostat.client.osgi.service.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));
-        
-        // Interesting enought this comes back with all services listed in
-        // 1.) this bundles commands: META-IN/services/com.redhat.thermostat.common.cli.Command (7 Commands)
-        // 2.) commands provided by tools (6 commands)
-        // 3.) 3 more services, namely applicationService, AgentInfoDAO and the VmInformationService registered
-        //     by this bundle.
-        assertEquals(16, ctx.getAllServices().size());
-    }
-}
--- a/client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/cli/DumpHeapCommandTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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> arg = ArgumentCaptor.forClass(Runnable.class);
-        doAnswer(new Answer<Void>() {
-
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                arg.getValue().run();
-                return null;
-            }
-        }).when(impl).execute(eq(agentInfoDao), any(VmRef.class), arg.capture());
-
-        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));
-        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/src/test/java/com/redhat/thermostat/client/heap/cli/FindObjectsCommandTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.model.HeapInfo;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-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/src/test/java/com/redhat/thermostat/client/heap/cli/FindRootCommandTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.model.HeapInfo;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-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/src/test/java/com/redhat/thermostat/client/heap/cli/HeapDumperCommandTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,138 +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.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.appctx.ApplicationContextUtil;
-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.model.AgentInformation;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-
-public class HeapDumperCommandTest {
-
-    private AgentInfoDAO agentInfoDao;
-    private HeapDumperCommand cmd;
-    private VmRef vmRef;
-    private RequestQueue reqQueue;
-    private Runnable heapDumpCompleteAction;
-
-    @Before
-    public void setUp() {
-        ApplicationContextUtil.resetApplicationContext();
-
-        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);
-
-    }
-
-    @After
-    public void tearDown() {
-        heapDumpCompleteAction = null;
-        vmRef = null;
-        cmd = null;
-        reqQueue = null;
-        ApplicationContextUtil.resetApplicationContext();
-    }
-
-    @Test
-	public void testExecute() {
-
-        cmd.execute(agentInfoDao, vmRef, heapDumpCompleteAction);
-
-		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();
-    }
-
-    private void verifyClassExists(String receiver) {
-        try {
-            Class.forName(receiver);
-        } catch (ClassNotFoundException e) {
-            throw new AssertionFailedError();
-        }
-    }
-
-}
--- a/client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/cli/ListHeapDumpsCommandTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.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.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
-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.model.HeapInfo;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-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);
-    }
-
-    @Before
-    public void setUp() {
-        ApplicationContextUtil.resetApplicationContext();
-    }
-
-    @After
-    public void tearDown() {
-        ApplicationContextUtil.resetApplicationContext();
-
-    }
-
-    @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/src/test/java/com/redhat/thermostat/client/heap/cli/ObjectInfoCommandTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.model.HeapInfo;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-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/src/test/java/com/redhat/thermostat/client/heap/cli/SaveHeapDumpToFileCommandTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.model.HeapInfo;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-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/src/test/java/com/redhat/thermostat/client/heap/cli/ShowHeapHistogramCommandTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.model.HeapInfo;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-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/src/test/java/com/redhat/thermostat/client/heap/swing/HeapDetailsSwingTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.swing.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/src/test/java/com/redhat/thermostat/client/heap/swing/HeapSwingViewTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-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/src/test/java/com/redhat/thermostat/client/heap/swing/ObjectDetailsPanelTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.heap.HeapObjectUI;
-import com.redhat.thermostat.client.heap.ObjectDetailsView.ObjectAction;
-import com.redhat.thermostat.client.ui.SearchFieldView;
-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/src/test/java/com/redhat/thermostat/client/heap/swing/ObjectRootsFrameTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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);
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,144 @@
+<?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>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/Activator.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.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.client.osgi.service.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();
+        }
+        
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/HeapDetailsSwing.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/HeapPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/HeapSwingView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,230 @@
+/*
+ * 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.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);
+            }
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/HistogramPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/LazyMutableTreeNode.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/ObjectDetailsPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,435 @@
+/*
+ * 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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/ObjectRootsFrame.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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);
+            }
+        });
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/StatsPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/SwingHeapDumpDetailsViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/SwingHeapHistogramViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/SwingHeapViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/SwingObjectDetailsViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/main/java/com/redhat/thermostat/client/heap/swing/SwingObjectRootsViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/test/java/com/redhat/thermostat/client/heap/swing/HeapDetailsSwingTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,151 @@
+/*
+ * 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();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/test/java/com/redhat/thermostat/client/heap/swing/HeapSwingViewTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,110 @@
+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);
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/test/java/com/redhat/thermostat/client/heap/swing/ObjectDetailsPanelTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,189 @@
+/*
+ * 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());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/test/java/com/redhat/thermostat/client/heap/swing/ObjectRootsFrameTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/heapdumper/swing/src/test/java/com/redhat/thermostat/client/heap/swing/ServicesAvailableActionTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.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.client.osgi.service.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());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/living-vm-filter/core/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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-osgi-living-vm-filter</artifactId>
+    <groupId>com.redhat.thermostat</groupId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>thermostat-osgi-living-vm-filter-core</artifactId>
+  <packaging>bundle</packaging>
+  <name>Thermostat Client Living VM Filter VM Lister Core</name>
+  <build>
+  
+    <resources>
+      <resource>  
+        <directory>src/main/resources</directory>
+        <filtering>false</filtering>
+      </resource>
+    </resources>
+  
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>com.redhat.thermostat.client.filter.vm.core</Export-Package>
+            <Bundle-Activator>com.redhat.thermostat.client.filter.vm.core.VMFilterActivator</Bundle-Activator>
+            <Bundle-SymbolicName>com.redhat.thermostat.filter.livingvm.core</Bundle-SymbolicName>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <!-- 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.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>
+
+  </dependencies>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/living-vm-filter/core/src/main/java/com/redhat/thermostat/client/filter/vm/core/LivingVMFilter.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.filter.vm.core;
+
+import com.redhat.thermostat.client.core.VmFilter;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.model.VmInfo;
+
+public class LivingVMFilter implements VmFilter {
+
+    volatile boolean filterActive = true;
+    
+    private VmInfoDAO dao;
+    
+    public LivingVMFilter(VmInfoDAO dao) {
+        this.dao = dao;
+    }
+    
+    @Override
+    public boolean matches(VmRef ref) {
+        if (!filterActive)
+            return true;
+
+        VmInfo vmInfo = dao.getVmInfo(ref);
+        return vmInfo.isAlive();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/living-vm-filter/core/src/main/java/com/redhat/thermostat/client/filter/vm/core/LivingVMFilterMenuAction.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.filter.vm.core;
+
+import com.redhat.thermostat.client.osgi.service.MenuAction;
+
+class LivingVMFilterMenuAction implements MenuAction {
+
+    private LivingVMFilter filter;
+    
+    public LivingVMFilterMenuAction(LivingVMFilter filter) {
+        this.filter = filter;
+    }
+    
+    @Override
+    public String getName() {
+        return "Show Non Living VM";
+    }
+
+    @Override
+    public String getDescription() {
+        return "Shows non living VM in the vm list";
+    }
+
+    @Override
+    public void execute() {
+        filter.filterActive = !filter.filterActive;
+    }
+
+    @Override
+    public Type getType() {
+        return Type.CHECK;
+    }
+
+    @Override
+    public String[] getPath() {
+        return new String[] { "Edit", getName() };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/living-vm-filter/core/src/main/java/com/redhat/thermostat/client/filter/vm/core/VMFilterActivator.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,108 @@
+/*
+ * 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.filter.vm.core;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+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.client.core.VmFilter;
+import com.redhat.thermostat.client.osgi.service.MenuAction;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
+
+public class VMFilterActivator implements BundleActivator {
+
+    private final List<ServiceRegistration> registeredServices = Collections.synchronizedList(new ArrayList<ServiceRegistration>());
+
+    ServiceTracker vmInfoDaoTracker;
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        
+        vmInfoDaoTracker = new ServiceTracker(context, VmInfoDAO.class.getName(), null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                VmInfoDAO dao = (VmInfoDAO) context.getService(reference);
+
+                LivingVMFilter filter = new LivingVMFilter(dao);
+                
+                LivingVMFilterMenuAction menu = new LivingVMFilterMenuAction(filter);
+
+                ServiceRegistration registration = null;
+                
+                registration = context.registerService(MenuAction.class.getName(), menu, null);
+                registeredServices.add(registration);
+
+                registration = context.registerService(VmFilter.class.getName(), filter, null);
+                registeredServices.add(registration);
+
+                return super.addingService(reference);
+            }
+
+            @Override
+            public void removedService(ServiceReference reference, Object service) {
+                Iterator<ServiceRegistration> iterator = registeredServices.iterator();
+                while(iterator.hasNext()) {
+                    ServiceRegistration registration = iterator.next();
+                    registration.unregister();
+                    iterator.remove();
+                }
+
+                context.ungetService(reference);
+                super.removedService(reference, service);
+            }
+        };
+        vmInfoDaoTracker.open();
+    }
+    
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        vmInfoDaoTracker.close();
+        
+        for (ServiceRegistration registration : registeredServices) {
+            registration.unregister();
+        }
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/living-vm-filter/core/src/test/java/com/redhat/thermostat/client/filter/vm/core/LivingVMFilterTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,93 @@
+/*
+ * 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.filter.vm.core;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.client.filter.vm.core.LivingVMFilter;
+import com.redhat.thermostat.client.filter.vm.core.LivingVMFilterMenuAction;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.model.VmInfo;
+
+public class LivingVMFilterTest {
+
+    private VmInfoDAO dao;
+    private VmRef vmRef1;
+    private VmRef vmRef2;
+    
+    private VmInfo vmInfo1;
+    private VmInfo vmInfo2;
+    
+    @Before
+    public void setUp() {
+        dao = mock(VmInfoDAO.class);
+        
+        vmRef1 = mock(VmRef.class);
+        vmRef2 = mock(VmRef.class);
+        
+        vmInfo1 = mock(VmInfo.class);
+        vmInfo2 = mock(VmInfo.class);
+        
+        when(dao.getVmInfo(vmRef1)).thenReturn(vmInfo1);
+        when(dao.getVmInfo(vmRef2)).thenReturn(vmInfo2);
+        
+        when(vmInfo1.isAlive()).thenReturn(true);
+        when(vmInfo2.isAlive()).thenReturn(false);
+    }
+    
+    @Test
+    public void testFilter() {
+        LivingVMFilter filter = new LivingVMFilter(dao);
+        LivingVMFilterMenuAction action = new LivingVMFilterMenuAction(filter);
+        
+        assertTrue(filter.matches(vmRef1));
+        assertFalse(filter.matches(vmRef2));
+        
+        action.execute();
+        
+        assertTrue(filter.matches(vmRef1));
+        assertTrue(filter.matches(vmRef2));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/living-vm-filter/core/src/test/java/com/redhat/thermostat/client/filter/vm/core/VMFilterActivatorTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,68 @@
+/*
+ * 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.filter.vm.core;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.client.core.VmFilter;
+import com.redhat.thermostat.client.osgi.service.MenuAction;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
+import com.redhat.thermostat.test.StubBundleContext;
+import com.redhat.thermostat.test.StubServiceReference;
+import com.redhat.thermostat.test.StubServiceRegistration;
+
+public class VMFilterActivatorTest {
+    
+    @Test
+    public void testServicesRegistered() throws Exception {
+        StubBundleContext ctx = new StubBundleContext();
+        VMFilterActivator activator = new VMFilterActivator();
+        activator.start(ctx);
+        
+        VmInfoDAO dao = mock(VmInfoDAO.class);
+        StubServiceRegistration reg = (StubServiceRegistration) ctx.registerService(VmInfoDAO.class, dao, null);
+        StubServiceReference ref = new StubServiceReference(reg.getInfo());
+        activator.vmInfoDaoTracker.addingService(ref);
+        
+        assertTrue(ctx.isServiceRegistered(MenuAction.class.getName(), LivingVMFilterMenuAction.class));
+        assertTrue(ctx.isServiceRegistered(VmFilter.class.getName(), LivingVMFilter.class));
+    }
+
+}
--- a/client/living-vm-filter/pom.xml	Fri Oct 26 13:13:42 2012 +0200
+++ b/client/living-vm-filter/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -1,79 +1,58 @@
 <?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>
-    <groupId>com.redhat.thermostat</groupId>
     <version>0.5.0-SNAPSHOT</version>
   </parent>
+
   <artifactId>thermostat-osgi-living-vm-filter</artifactId>
-  <packaging>bundle</packaging>
+  <packaging>pom</packaging>
+
   <name>Thermostat Client Living VM Filter VM Lister</name>
-  <build>
-  
-  
-    <resources>
-      <resource>
-        <directory>src/main/resources</directory>
-        <filtering>false</filtering>
-      </resource>
-    </resources>
-  
-  
-    <plugins>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <configuration>
-          <instructions>
-            <Private-Package>com.redhat.thermostat.client.filter.vm</Private-Package>
-            <Bundle-Activator>com.redhat.thermostat.client.filter.vm.VMFilterActivator</Bundle-Activator>
-            <Bundle-SymbolicName>com.redhat.thermostat.filter.livingvm</Bundle-SymbolicName>
-            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
-            <!-- 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.osgi</groupId>
-      <artifactId>org.osgi.core</artifactId>
-      <scope>provided</scope>
-    </dependency>
+  <modules>
+    <module>core</module>
+    <module>swing</module>
+  </modules>
 
-    <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>
-
-  </dependencies>
 </project>
--- a/client/living-vm-filter/src/main/java/com/redhat/thermostat/client/filter/vm/DeadVMDecorator.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +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.filter.vm;
-
-import java.io.IOException;
-
-import com.redhat.thermostat.client.core.VmFilter;
-import com.redhat.thermostat.client.osgi.service.VmDecorator;
-import com.redhat.thermostat.client.ui.Decorator;
-import com.redhat.thermostat.client.ui.IconDescriptor;
-import com.redhat.thermostat.common.dao.VmInfoDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.model.VmInfo;
-
-public class DeadVMDecorator implements VmDecorator {
-    
-    private class VMDecorator implements Decorator {
-        @Override
-        public IconDescriptor getIconDescriptor() {
-            try {
-                return IconDescriptor.createFromClassloader(getClass().getClassLoader(), "deadvm.png");
-            } catch (IOException e) {
-                e.printStackTrace();
-                return null;
-            }
-        }
-        
-        @Override
-        public String getLabel(String originalLabel) {
-            return "[not running] " + originalLabel;
-        }
-        
-        @Override
-        public Quadrant getQuadrant() {
-            return Quadrant.BOTTOM_LEFT;
-        }
-    }
-
-    private VmFilter decoratorFilter;
-    private VMDecorator decorator;
-    
-    public DeadVMDecorator(final VmInfoDAO dao) {
-        decorator = new VMDecorator();
-        decoratorFilter = new VmFilter() {
-            @Override
-            public boolean matches(VmRef vm) {
-                VmInfo vmInfo = dao.getVmInfo(vm);
-
-                return !vmInfo.isAlive();
-            }
-        };
-    }
-    
-    @Override
-    public Decorator getDecorator() {
-        return decorator;
-    }
-    
-    @Override
-    public VmFilter getFilter() {
-        return decoratorFilter;
-    }
-}
--- a/client/living-vm-filter/src/main/java/com/redhat/thermostat/client/filter/vm/LivingVMFilter.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.filter.vm;
-
-import com.redhat.thermostat.client.core.VmFilter;
-import com.redhat.thermostat.common.dao.VmInfoDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.model.VmInfo;
-
-public class LivingVMFilter implements VmFilter {
-
-    volatile boolean filterActive = true;
-    
-    private VmInfoDAO dao;
-    
-    public LivingVMFilter(VmInfoDAO dao) {
-        this.dao = dao;
-    }
-    
-    @Override
-    public boolean matches(VmRef ref) {
-        if (!filterActive)
-            return true;
-
-        VmInfo vmInfo = dao.getVmInfo(ref);
-        return vmInfo.isAlive();
-    }
-}
--- a/client/living-vm-filter/src/main/java/com/redhat/thermostat/client/filter/vm/LivingVMFilterMenuAction.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.client.filter.vm;
-
-import com.redhat.thermostat.client.osgi.service.MenuAction;
-
-class LivingVMFilterMenuAction implements MenuAction {
-
-    private LivingVMFilter filter;
-    
-    public LivingVMFilterMenuAction(LivingVMFilter filter) {
-        this.filter = filter;
-    }
-    
-    @Override
-    public String getName() {
-        return "Show Non Living VM";
-    }
-
-    @Override
-    public String getDescription() {
-        return "Shows non living VM in the vm list";
-    }
-
-    @Override
-    public void execute() {
-        filter.filterActive = !filter.filterActive;
-    }
-
-    @Override
-    public Type getType() {
-        return Type.CHECK;
-    }
-
-    @Override
-    public String[] getPath() {
-        return new String[] { "Edit", getName() };
-    }
-}
--- a/client/living-vm-filter/src/main/java/com/redhat/thermostat/client/filter/vm/VMDecorator.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +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.filter.vm;
-
-import java.io.IOException;
-
-import com.redhat.thermostat.client.core.VmFilter;
-import com.redhat.thermostat.client.osgi.service.VmDecorator;
-import com.redhat.thermostat.client.ui.Decorator;
-import com.redhat.thermostat.client.ui.IconDescriptor;
-import com.redhat.thermostat.client.ui.IconResource;
-import com.redhat.thermostat.common.dao.VmInfoDAO;
-
-public class VMDecorator implements VmDecorator {
-    
-    private class LivingVMDecorator implements Decorator {
-        @Override
-        public IconDescriptor getIconDescriptor() {
-            try {
-                return IconDescriptor.createFromClassloader(IconDescriptor.class.getClassLoader(), IconResource.JAVA_APPLICATION.getPath());
-            } catch (IOException e) {
-                e.printStackTrace();
-                return null;
-            }
-        }
-        
-        @Override
-        public String getLabel(String originalLabel) {
-            return originalLabel;
-        }
-        
-        @Override
-        public Quadrant getQuadrant() {
-            return Quadrant.MAIN;
-        }
-    }
-
-    private LivingVMFilter decoratorFilter;
-    private LivingVMDecorator decorator;
-    
-    public VMDecorator(VmInfoDAO dao) {
-        decorator = new LivingVMDecorator();
-        decoratorFilter = new LivingVMFilter(dao);
-    }
-    
-    @Override
-    public Decorator getDecorator() {
-        return decorator;
-    }
-    
-    @Override
-    public VmFilter getFilter() {
-        return decoratorFilter;
-    }
-}
--- a/client/living-vm-filter/src/main/java/com/redhat/thermostat/client/filter/vm/VMFilterActivator.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.filter.vm;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-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.client.core.VmFilter;
-import com.redhat.thermostat.client.osgi.service.MenuAction;
-import com.redhat.thermostat.client.osgi.service.VmDecorator;
-import com.redhat.thermostat.common.dao.VmInfoDAO;
-
-public class VMFilterActivator implements BundleActivator {
-
-    private final List<ServiceRegistration> registeredServices = Collections.synchronizedList(new ArrayList<ServiceRegistration>());
-
-    private ServiceTracker vmInfoDaoTracker;
-
-    @Override
-    public void start(BundleContext context) throws Exception {
-        
-        vmInfoDaoTracker = new ServiceTracker(context, VmInfoDAO.class.getName(), null) {
-            @Override
-            public Object addingService(ServiceReference reference) {
-                VmInfoDAO dao = (VmInfoDAO) context.getService(reference);
-
-                LivingVMFilter filter = new LivingVMFilter(dao);
-                VMDecorator decorator = new VMDecorator(dao);
-                DeadVMDecorator deadDecorator = new DeadVMDecorator(dao);
-                
-                LivingVMFilterMenuAction menu = new LivingVMFilterMenuAction(filter);
-
-                ServiceRegistration registration = null;
-                
-                registration = context.registerService(MenuAction.class.getName(), menu, null);
-                registeredServices.add(registration);
-
-                registration = context.registerService(VmDecorator.class.getName(), deadDecorator, null);
-                registeredServices.add(registration);
-
-                registration = context.registerService(VmDecorator.class.getName(), decorator, null);
-                registeredServices.add(registration);
-
-                registration = context.registerService(VmFilter.class.getName(), filter, null);
-                registeredServices.add(registration);
-
-                return super.addingService(reference);
-            }
-
-            @Override
-            public void removedService(ServiceReference reference, Object service) {
-                Iterator<ServiceRegistration> iterator = registeredServices.iterator();
-                while(iterator.hasNext()) {
-                    ServiceRegistration registration = iterator.next();
-                    registration.unregister();
-                    iterator.remove();
-                }
-
-                context.ungetService(reference);
-                super.removedService(reference, service);
-            }
-        };
-        vmInfoDaoTracker.open();
-    }
-    
-    @Override
-    public void stop(BundleContext context) throws Exception {
-        vmInfoDaoTracker.close();
-        
-        for (ServiceRegistration registration : registeredServices) {
-            registration.unregister();
-        }
-    }
-}
Binary file client/living-vm-filter/src/main/resources/deadvm.png has changed
--- a/client/living-vm-filter/src/test/java/com/redhat/thermostat/client/filter/vm/LivingVMFilterTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +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.filter.vm;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.common.dao.VmInfoDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.model.VmInfo;
-
-public class LivingVMFilterTest {
-
-    private VmInfoDAO dao;
-    private VmRef vmRef1;
-    private VmRef vmRef2;
-    
-    private VmInfo vmInfo1;
-    private VmInfo vmInfo2;
-    
-    @Before
-    public void setUp() {
-        dao = mock(VmInfoDAO.class);
-        
-        vmRef1 = mock(VmRef.class);
-        vmRef2 = mock(VmRef.class);
-        
-        vmInfo1 = mock(VmInfo.class);
-        vmInfo2 = mock(VmInfo.class);
-        
-        when(dao.getVmInfo(vmRef1)).thenReturn(vmInfo1);
-        when(dao.getVmInfo(vmRef2)).thenReturn(vmInfo2);
-        
-        when(vmInfo1.isAlive()).thenReturn(true);
-        when(vmInfo2.isAlive()).thenReturn(false);
-    }
-    
-    @Test
-    public void testFilter() {
-        LivingVMFilter filter = new LivingVMFilter(dao);
-        LivingVMFilterMenuAction action = new LivingVMFilterMenuAction(filter);
-        
-        assertTrue(filter.matches(vmRef1));
-        assertFalse(filter.matches(vmRef2));
-        
-        action.execute();
-        
-        assertTrue(filter.matches(vmRef1));
-        assertTrue(filter.matches(vmRef2));
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/living-vm-filter/swing/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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-osgi-living-vm-filter</artifactId>
+    <groupId>com.redhat.thermostat</groupId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>thermostat-osgi-living-vm-filter-swing</artifactId>
+  <packaging>bundle</packaging>
+  <name>Thermostat Client Living VM Filter VM Lister Swing</name>
+  <build>
+  
+  
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>false</filtering>
+      </resource>
+    </resources>
+  
+  
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Private-Package>com.redhat.thermostat.client.filter.vm.swing</Private-Package>
+            <Bundle-Activator>com.redhat.thermostat.client.filter.vm.swing.VMFilterActivator</Bundle-Activator>
+            <Bundle-SymbolicName>com.redhat.thermostat.filter.livingvm.swing</Bundle-SymbolicName>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <!-- 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.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-osgi-living-vm-filter-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-client-swing</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+  </dependencies>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/living-vm-filter/swing/src/main/java/com/redhat/thermostat/client/filter/vm/swing/DeadVMDecorator.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,97 @@
+/*
+ * 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.filter.vm.swing;
+
+import java.io.IOException;
+
+import com.redhat.thermostat.client.core.VmFilter;
+import com.redhat.thermostat.client.osgi.service.VmDecorator;
+import com.redhat.thermostat.client.ui.Decorator;
+import com.redhat.thermostat.client.ui.IconDescriptor;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.model.VmInfo;
+
+public class DeadVMDecorator implements VmDecorator {
+    
+    private class VMDecorator implements Decorator {
+        @Override
+        public IconDescriptor getIconDescriptor() {
+            try {
+                return IconDescriptor.createFromClassloader(getClass().getClassLoader(), "deadvm.png");
+            } catch (IOException e) {
+                e.printStackTrace();
+                return null;
+            }
+        }
+        
+        @Override
+        public String getLabel(String originalLabel) {
+            return "[not running] " + originalLabel;
+        }
+        
+        @Override
+        public Quadrant getQuadrant() {
+            return Quadrant.BOTTOM_LEFT;
+        }
+    }
+
+    private VmFilter decoratorFilter;
+    private VMDecorator decorator;
+    
+    public DeadVMDecorator(final VmInfoDAO dao) {
+        decorator = new VMDecorator();
+        decoratorFilter = new VmFilter() {
+            @Override
+            public boolean matches(VmRef vm) {
+                VmInfo vmInfo = dao.getVmInfo(vm);
+
+                return !vmInfo.isAlive();
+            }
+        };
+    }
+    
+    @Override
+    public Decorator getDecorator() {
+        return decorator;
+    }
+    
+    @Override
+    public VmFilter getFilter() {
+        return decoratorFilter;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/living-vm-filter/swing/src/main/java/com/redhat/thermostat/client/filter/vm/swing/VMDecorator.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,90 @@
+/*
+ * 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.filter.vm.swing;
+
+import java.io.IOException;
+
+import com.redhat.thermostat.client.core.VmFilter;
+import com.redhat.thermostat.client.filter.vm.core.LivingVMFilter;
+import com.redhat.thermostat.client.osgi.service.VmDecorator;
+import com.redhat.thermostat.client.swing.IconResource;
+import com.redhat.thermostat.client.ui.Decorator;
+import com.redhat.thermostat.client.ui.IconDescriptor;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
+
+public class VMDecorator implements VmDecorator {
+    
+    private class LivingVMDecorator implements Decorator {
+        @Override
+        public IconDescriptor getIconDescriptor() {
+            try {
+                return IconDescriptor.createFromClassloader(IconResource.class.getClassLoader(), IconResource.JAVA_APPLICATION.getPath());
+            } catch (IOException e) {
+                e.printStackTrace();
+                return null;
+            }
+        }
+        
+        @Override
+        public String getLabel(String originalLabel) {
+            return originalLabel;
+        }
+        
+        @Override
+        public Quadrant getQuadrant() {
+            return Quadrant.MAIN;
+        }
+    }
+
+    private LivingVMFilter decoratorFilter;
+    private LivingVMDecorator decorator;
+    
+    public VMDecorator(VmInfoDAO dao) {
+        decorator = new LivingVMDecorator();
+        decoratorFilter = new LivingVMFilter(dao);
+    }
+    
+    @Override
+    public Decorator getDecorator() {
+        return decorator;
+    }
+    
+    @Override
+    public VmFilter getFilter() {
+        return decoratorFilter;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/living-vm-filter/swing/src/main/java/com/redhat/thermostat/client/filter/vm/swing/VMFilterActivator.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,105 @@
+/*
+ * 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.filter.vm.swing;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+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.client.osgi.service.VmDecorator;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
+
+public class VMFilterActivator implements BundleActivator {
+
+    private final List<ServiceRegistration> registeredServices = Collections.synchronizedList(new ArrayList<ServiceRegistration>());
+
+    ServiceTracker vmInfoDaoTracker;
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        
+        vmInfoDaoTracker = new ServiceTracker(context, VmInfoDAO.class.getName(), null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                VmInfoDAO dao = (VmInfoDAO) context.getService(reference);
+
+                VMDecorator decorator = new VMDecorator(dao);
+                DeadVMDecorator deadDecorator = new DeadVMDecorator(dao);
+                
+                ServiceRegistration registration = null;
+                
+                registration = context.registerService(VmDecorator.class.getName(), deadDecorator, null);
+                registeredServices.add(registration);
+
+                registration = context.registerService(VmDecorator.class.getName(), decorator, null);
+                registeredServices.add(registration);
+
+                return super.addingService(reference);
+            }
+
+            @Override
+            public void removedService(ServiceReference reference, Object service) {
+                Iterator<ServiceRegistration> iterator = registeredServices.iterator();
+                while(iterator.hasNext()) {
+                    ServiceRegistration registration = iterator.next();
+                    registration.unregister();
+                    iterator.remove();
+                }
+
+                context.ungetService(reference);
+                super.removedService(reference, service);
+            }
+        };
+        vmInfoDaoTracker.open();
+    }
+    
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        vmInfoDaoTracker.close();
+        
+        for (ServiceRegistration registration : registeredServices) {
+            registration.unregister();
+        }
+    }
+}
Binary file client/living-vm-filter/swing/src/main/resources/deadvm.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/living-vm-filter/swing/src/test/java/com/redhat/thermostat/client/filter/vm/swing/VMFilterActivatorTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.filter.vm.swing;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.client.osgi.service.VmDecorator;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
+import com.redhat.thermostat.test.StubBundleContext;
+import com.redhat.thermostat.test.StubServiceReference;
+import com.redhat.thermostat.test.StubServiceRegistration;
+
+public class VMFilterActivatorTest {
+    
+    @Test
+    public void testServicesRegistered() throws Exception {
+        StubBundleContext ctx = new StubBundleContext();
+        VMFilterActivator activator = new VMFilterActivator();
+        activator.start(ctx);
+        
+        VmInfoDAO dao = mock(VmInfoDAO.class);
+        StubServiceRegistration reg = (StubServiceRegistration) ctx.registerService(VmInfoDAO.class, dao, null);
+        StubServiceReference ref = new StubServiceReference(reg.getInfo());
+        activator.vmInfoDaoTracker.addingService(ref);
+        
+        assertTrue(ctx.isServiceRegistered(VmDecorator.class.getName(), VMDecorator.class));
+        assertTrue(ctx.isServiceRegistered(VmDecorator.class.getName(), DeadVMDecorator.class));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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-osgi-memory-stats-panel</artifactId>
+    <groupId>com.redhat.thermostat</groupId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>thermostat-osgi-memory-stats-panel-core</artifactId>
+  <packaging>bundle</packaging>
+  <name>Thermostat Client VM Memory Monitor Core plugin</name>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+                com.redhat.thermostat.client.stats.memory.core,
+                   com.redhat.thermostat.client.stats.memory.core.locale,
+            </Export-Package>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-SymbolicName>com.redhat.thermostat.client.stats.memory.core</Bundle-SymbolicName>
+            <!-- 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.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>org.jfree</groupId>
+      <artifactId>jfreechart</artifactId>
+    </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>
+  </dependencies>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/MemoryMeter.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,433 @@
+/*
+ * 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.stats.memory.core;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Insets;
+import java.awt.Paint;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
+import java.awt.image.BufferedImage;
+import java.beans.Transient;
+
+import javax.swing.JComponent;
+import javax.swing.plaf.ColorUIResource;
+
+import sun.swing.SwingUtilities2;
+
+@SuppressWarnings({ "restriction", "serial" })
+public class MemoryMeter extends JComponent {
+    
+    // TODO the font should be customizable
+    private static final Font font = new Font("SansSerif", Font.PLAIN, 10);
+    
+    private static final int TICK_NUM = 100;
+    private static final int SMALL_TICK_NUM = 5;
+    
+    private static final int MAIN_BAR_HEIGHT = 20;
+    
+    private static final ColorUIResource MAIN_GRADIENT_TOP = new ColorUIResource(0xf1f3f1);
+    private static final ColorUIResource MAIN_BORDER_COLOR = new ColorUIResource(0xa8aca8);
+    
+    private static final ColorUIResource MAIN_BAR_BASE_COLOR_TOP = new ColorUIResource(0xbcd5ef);
+    private static final ColorUIResource MAIN_BAR_BASE_COLOR = new ColorUIResource(0x4A90D9);
+    
+    //private static final ColorUIResource STATS_BG = new ColorUIResource(0xF8F8F8);
+    private static final ColorUIResource STATS_BG = new ColorUIResource(0xFFFFFF);
+    
+    private ColorUIResource tickColor;
+    
+    private RangeModel primary;
+    private RangeModel secondary;
+    
+    private Insets boundInsets;
+    
+    private RangeModel internalSecondaryModel;
+    
+    private StatsModel primaryStats;
+    
+    private String primaryUnit;
+    private String secondaryUnit;
+
+        public void setPrimaryScaleUnit(String primaryUnit) {
+        this.primaryUnit = primaryUnit;
+    }
+    
+    public void setSecondayScaleUnit(String secondaryUnit) {
+        this.secondaryUnit = secondaryUnit;
+    }
+    
+    public StatsModel getStats() {
+        return primaryStats;
+    }
+    
+    public void setStats(StatsModel primaryStats) {
+        this.primaryStats = primaryStats;
+    }
+
+    public MemoryMeter() {
+        
+        secondaryUnit = "";
+        primaryUnit = "";
+        
+        boundInsets = new Insets(10, 10, 20, 20);
+        
+        tickColor = new ColorUIResource(0xdbdddb);
+        
+        primary = new RangeModel();
+        primary.setMinimum(0);
+        primary.setMaximum(100);
+        primary.setMinNormalized(0);
+        primary.setMaxNormalized(100);
+        
+        secondary = new RangeModel();
+        secondary.setMinimum(0);
+        secondary.setMaximum(100);
+        secondary.setMinNormalized(0);
+        secondary.setMaxNormalized(100);
+        
+        internalSecondaryModel = new RangeModel();
+    }
+    
+    public ColorUIResource getTickColor() {
+        return tickColor;
+    }
+    
+    public void setTickColor(ColorUIResource tickColor) {
+        this.tickColor = tickColor;
+    }
+    
+    public RangeModel getPrimaryModel() {
+        return primary;
+    }
+    
+    public RangeModel getSecondaryModel() {
+        return secondary;
+    }
+    
+    protected Rectangle getOuterBounds() {
+        return new Rectangle(0, 0, getWidth(), getHeight());
+    }
+    
+    protected Rectangle getBoundsWithInsets(Rectangle bounds) {
+        return new Rectangle(bounds.x + boundInsets.left,
+                             bounds.y + boundInsets.top,
+                             bounds.width  - boundInsets.right,
+                             bounds.height - boundInsets.bottom);
+    }
+        
+    /**
+     * paint the outher frame, including the light border sorrounding
+     */
+    protected void paintOuterFrame(Graphics2D graphics, Rectangle bounds) {
+
+        RoundRectangle2D frame = new RoundRectangle2D.Float(bounds.x, bounds.y, bounds.width, bounds.height, 6, 6);
+
+        Paint paint = new GradientPaint(0, 0, MAIN_GRADIENT_TOP, 0, getHeight(), getBackground());
+        graphics.setPaint(paint);
+        graphics.fill(frame);
+        
+        paint = new GradientPaint(0, 0, MAIN_BORDER_COLOR, 0, getHeight(), getBackground());
+        graphics.setPaint(paint);
+        frame = new RoundRectangle2D.Float(bounds.x, bounds.y, bounds.width -1, bounds.height, 6, 6);
+        graphics.draw(frame);
+    }
+    
+    /**
+     * paint the track sorrounding the main bar
+     */
+    protected void paintMainBarTrackFill(Graphics2D graphics, Rectangle bounds) {
+        
+        Paint paint = new GradientPaint(0, 0, MAIN_GRADIENT_TOP, 0, bounds.height, Color.WHITE);
+        graphics.setPaint(paint);
+        RoundRectangle2D frame = new RoundRectangle2D.Float(0, 0, bounds.width, bounds.height, 6, 6);
+        graphics.fill(frame);
+    }
+    
+    /**
+     */
+    protected void paintMainBarTrackBorder(Graphics2D graphics, Rectangle bounds) {
+        Paint paint = new GradientPaint(0, 0, MAIN_BORDER_COLOR, getWidth(), 0, getBackground());
+        graphics.setPaint(paint);
+        
+        RoundRectangle2D frame = new RoundRectangle2D.Float(0, 0, bounds.width - 1, bounds.height, 6, 6);
+        graphics.draw(frame);
+    }
+
+    
+    /**
+     * this is the main bar, will it up to what is defined by the model
+     */
+    protected void paintMainBarFill(Graphics2D graphics, Rectangle bounds) {
+        Paint paint = new GradientPaint(0, 0, MAIN_BAR_BASE_COLOR, getWidth() * 2, 0, getBackground());
+        graphics.setPaint(paint);
+        
+        RoundRectangle2D frame =
+                new RoundRectangle2D.Float(0, 0, getPrimaryModel().getValueNormalized(),
+                                           bounds.height, 6, 6);
+        graphics.fill(frame);
+        
+        String value = String.valueOf(getPrimaryModel().getValue()) + " " + primaryUnit;
+        Rectangle2D fontBounds = font.getStringBounds(value, graphics.getFontRenderContext());
+        int width = (int) (bounds.width/2 - fontBounds.getWidth()/2) - 1;
+        
+        if (width > getPrimaryModel().getValueNormalized()) {
+            graphics.setPaint(MAIN_BAR_BASE_COLOR);
+        } else {
+            graphics.setPaint(getBackground());
+        }
+
+        int height  = (int) (bounds.height / 2 + fontBounds.getHeight()/2);
+        SwingUtilities2.drawString(this, graphics, value, width, height);
+    }
+    
+    /**
+     */
+    private void paintMainBar(Graphics2D g, Rectangle bounds) {
+        
+        Graphics2D graphics = (Graphics2D) g.create();
+                
+        graphics.translate(bounds.x, bounds.y);
+        paintMainBarTrackFill(graphics, bounds);
+        
+        paintMainBarFill(graphics, bounds);
+        
+        paintMainBarTrackBorder(graphics, bounds);
+        graphics.dispose();
+    }
+    
+    /**
+     */
+    protected void drawBottomBar(Graphics2D g, Rectangle bounds) {
+
+        Graphics2D graphics = (Graphics2D) g.create();
+        graphics.translate(bounds.x, bounds.y + bounds.height);
+        
+        drawTickMark(graphics, bounds);
+        
+        paintSecondaryBarFill(graphics, bounds);
+        
+        graphics.dispose();
+    }
+    
+    /**
+     */
+    protected void drawTickMark(Graphics2D graphics, Rectangle bounds) {
+      
+        graphics.setPaint(MAIN_BORDER_COLOR);
+        
+        int smallTop = bounds.height - 5;
+        int smallBottom = bounds.height;
+
+        int mainTop = smallTop + 20;
+        int mainBottom = smallBottom - 15;
+      
+        // the first and last tick are always big, this is the first
+        graphics.drawLine(0, mainTop, 0, mainBottom);
+      
+        // the space between the vertical lines
+        double tickSpace = ((double) bounds.width) / TICK_NUM;
+      
+        internalSecondaryModel.setMaxNormalized(bounds.width);      
+        int numTicks = 0;
+
+        for (int x = 0; x < bounds.width; x += tickSpace + 0.5) {
+            if (numTicks % SMALL_TICK_NUM == 0) {
+              
+                graphics.drawLine(x, smallTop, x, smallBottom + 5);
+
+                internalSecondaryModel.setValue(x);
+            } else {
+                graphics.drawLine(x, smallTop, x, smallBottom);
+            }
+            numTicks++;
+        }
+        
+        // that's the last
+        graphics.drawLine(bounds.width, mainTop, bounds.width, mainBottom);
+        graphics.drawLine(0, smallTop, bounds.width, smallTop);
+        
+        drawStrings(graphics, mainBottom, mainTop, bounds.width);
+    }
+    
+    protected void drawStrings(Graphics2D graphics, int top, int bottom, int right) {
+      
+      // now draw the min/max values of both side of markers      
+      // top bar min value
+      FontMetrics fm = SwingUtilities2.getFontMetrics(this, font);
+      
+      String value = String.valueOf(getPrimaryModel().getMinimum()) + " " + primaryUnit;
+      int height = top + fm.getAscent()/2;
+      SwingUtilities2.drawString(this, graphics, value, 1, height);
+      
+      value = String.valueOf(getSecondaryModel().getMinimum()) + " " + secondaryUnit;
+      height = bottom;
+      SwingUtilities2.drawString(this, graphics, value, 1, height);
+      
+      value = String.valueOf(getPrimaryModel().getMaximum()) + " " + primaryUnit;
+      height = top + fm.getAscent()/2;
+
+      int width = (int) (right - font.getStringBounds(value, graphics.getFontRenderContext()).getWidth()) - 1;
+      SwingUtilities2.drawString(this, graphics, value, width, height);
+      
+      value = String.valueOf(getSecondaryModel().getMaximum()) + " " + secondaryUnit;
+      height = bottom;
+      width = (int) (right - font.getStringBounds(value, graphics.getFontRenderContext()).getWidth()) - 1;
+      SwingUtilities2.drawString(this, graphics, value, width, height);
+      
+      // now draw the actual value for the bottom bar, the top bar is drawn in
+      // its fill method
+      value = String.valueOf(getSecondaryModel().getValue()) + " " + secondaryUnit;
+      width = right/2;
+      Rectangle2D bounds = font.getStringBounds(value, graphics.getFontRenderContext());
+      width = (int) (width - bounds.getWidth()/2) - 1;
+      SwingUtilities2.drawString(this, graphics, value, width, height);
+      RoundRectangle2D frame = new RoundRectangle2D.Double(width - 2, height - bounds.getHeight(),
+                                                          bounds.getWidth() + 4, bounds.getHeight() + 4,
+                                                          4, 4);
+      graphics.draw(frame);
+    }
+    
+    protected void paintSecondaryBarFill(Graphics2D graphics, Rectangle bounds) {
+        
+        graphics.setPaint(MAIN_BAR_BASE_COLOR_TOP);
+        graphics.drawLine(1, bounds.height, getSecondaryModel().getValueNormalized() - 1, bounds.height);
+        
+        graphics.setPaint(MAIN_BAR_BASE_COLOR);
+        graphics.fillRect(1, bounds.height + 1, getSecondaryModel().getValueNormalized(), 2);
+    }
+    
+    protected void paintStats(Graphics2D graphics, Rectangle bounds) {
+        
+        int imageWidth = bounds.width - 2;
+        if (imageWidth < 0 || bounds.height < 0) {
+            return;
+        }
+        
+        StatsModel stats = getStats();
+        drawStats(graphics, stats, bounds.x, bounds.y, imageWidth, bounds.height);
+    }
+    
+    private void drawStats(Graphics2D graphics, StatsModel stats, int x, int y, int imageWidth, int height) {
+        if (stats != null) {
+            BufferedImage image = stats.getChart(imageWidth, height, STATS_BG,
+                                                 new ColorUIResource(getForeground()));
+       
+            paintStatsLabel(graphics, image, stats.getName());
+            graphics.drawImage(image, x, y, null);
+        }
+    }
+    
+    protected void paintStatsLabel(Graphics2D graphics, BufferedImage image, String label) {
+        int height = SwingUtilities2.getFontMetrics(this, font).getAscent() + 2;
+        if (height <= 0) {
+            return;
+        }
+        
+        Graphics2D imageGraphics = (Graphics2D) image.getGraphics();
+        imageGraphics.setColor(getForeground());
+        imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        
+        SwingUtilities2.drawString(this, imageGraphics, label, 2, height);
+    }
+    
+    @Override
+    protected void paintComponent(Graphics g) {
+
+        Graphics2D graphics = (Graphics2D) g.create();
+        graphics.setFont(font);
+        
+        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+        
+        Rectangle outerBounds = getOuterBounds();
+        Rectangle innerBounds = getBoundsWithInsets(outerBounds);
+        Rectangle statsBound =  getBoundsWithInsets(outerBounds);
+        
+        // move the bar close to the center
+        innerBounds.height = MAIN_BAR_HEIGHT;
+        innerBounds.y = outerBounds.height/2;
+        
+        // make the stats area cover the upper portion instead
+        statsBound.height = (outerBounds.height/2) - MAIN_BAR_HEIGHT;
+        
+        resetModels(0, innerBounds.width);
+
+        // some eye candy
+        paintOuterFrame(graphics, outerBounds);
+
+        // paint the usage stats
+        paintStats(graphics, statsBound);
+        
+        // main and bottom bars
+        paintMainBar(graphics, innerBounds);
+        drawBottomBar(graphics, innerBounds);
+        
+        graphics.dispose();
+    }
+    
+    private void resetModels(int min, int max) {
+        
+        getPrimaryModel().setMaxNormalized(max);
+        getPrimaryModel().setMinNormalized(min);
+        
+        RangeModel model = getSecondaryModel();
+        model.setMaxNormalized(max);
+        model.setMinNormalized(min);
+        
+        internalSecondaryModel.setMaximum(model.getMaximum());
+        internalSecondaryModel.setMinimum(model.getMinimum());
+        internalSecondaryModel.setValue(model.getValue());
+        
+        internalSecondaryModel.setMaxNormalized(max);
+        internalSecondaryModel.setMinNormalized(0);
+    }
+    
+    @Override
+    @Transient
+    public Dimension getPreferredSize() {
+        return new Dimension(850, 150);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/MemoryStatsController.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,228 @@
+/*
+ * 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.stats.memory.core;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+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.stats.memory.core.locale.LocaleResources;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.NotImplementedException;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.Timer.SchedulingType;
+import com.redhat.thermostat.common.appctx.ApplicationContext;
+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.model.VmMemoryStat;
+import com.redhat.thermostat.common.model.VmMemoryStat.Generation;
+import com.redhat.thermostat.common.model.VmMemoryStat.Space;
+import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
+
+class MemoryStatsController implements VmInformationServiceController {
+
+    private final MemoryStatsView view;
+    private final VmMemoryStatDAO vmDao;
+   
+    private final VmRef ref;
+    private final Timer timer;
+    
+    private final Map<String, Payload> regions;
+    
+    private VMCollector collector;
+    
+    class VMCollector implements Runnable {
+
+        private long desiredUpdateTimeStamp = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1);
+
+        @Override
+        public void run() {
+            List<VmMemoryStat> vmInfo = vmDao.getLatestVmMemoryStats(ref, desiredUpdateTimeStamp);
+            for (VmMemoryStat memoryStats: vmInfo) {
+                Generation[] generations = memoryStats.getGenerations();
+                
+                for (Generation generation : generations) {
+                    Space[] spaces = generation.getSpaces();
+                    for (Space space: spaces) {
+                        Payload payload = regions.get(space.getName());
+                        if (payload == null) {
+                            payload = new Payload();
+                            payload.setName(space.getName());
+                        }
+
+                        Scale usedScale = normalizeScale(space.getUsed(), space.getCapacity());
+                        double used = Scale.convertTo(usedScale, space.getUsed(), 100);
+                        double maxUsed = Scale.convertTo(usedScale, space.getCapacity(), 100);
+                        
+                        payload.setUsed(used);
+                        payload.setMaxUsed(maxUsed);
+                        payload.setUsedUnit(usedScale);
+                        
+                        Scale maxScale = normalizeScale(space.getCapacity(), space.getMaxCapacity());
+                        double capacity = Scale.convertTo(maxScale, space.getCapacity(), 100);
+                        double maxCapacity = Scale.convertTo(maxScale, space.getMaxCapacity(), 100);
+                        
+                        payload.setCapacity(capacity);
+                        payload.setMaxCapacity(maxCapacity);
+                        payload.setCapacityUnit(maxScale);
+                        
+                        String tooltip = space.getName() + ": used: " + used + " " + usedScale +
+                                ", capacity: " + capacity + " " + maxScale +
+                                ", max capacity: " + maxCapacity + " " + maxScale;
+                        
+                        payload.setTooltip(tooltip);
+                        
+                        StatsModel model = payload.getModel();
+                        if (model == null) {
+                            model = new StatsModel();
+                            model.setName(space.getName());
+                            model.setRange(3600);
+                        }
+                        
+                        // normalize this always in the same unit
+                        model.addData(memoryStats.getTimeStamp(),
+                                      Scale.convertTo(Scale.MiB, space.getUsed(), 100));
+                        
+                        payload.setModel(model);
+                        if (regions.containsKey(space.getName())) {
+                            view.updateRegion(payload.clone());
+                        } else {
+                            view.addRegion(payload.clone());
+                            regions.put(space.getName(), payload);
+                        }
+                        
+                        view.requestRepaint();
+                        desiredUpdateTimeStamp = Math.max(desiredUpdateTimeStamp, memoryStats.getTimeStamp());
+                    }
+                }
+            }
+        }
+    }
+    
+    public MemoryStatsController(final VmMemoryStatDAO vmMemoryStatDao, final VmRef ref, MemoryStatsViewProvider viewProvider) {
+        
+        regions = new HashMap<>();
+        this.ref = ref;
+        vmDao = vmMemoryStatDao;
+        view = viewProvider.createView();
+        
+        timer = ApplicationContext.getInstance().getTimerFactory().createTimer();
+        
+        collector = new VMCollector();
+        timer.setAction(collector);
+        
+        timer.setInitialDelay(0);
+        timer.setDelay(1000);
+        timer.setTimeUnit(TimeUnit.MILLISECONDS);
+        timer.setSchedulingType(SchedulingType.FIXED_RATE);
+
+        view.addActionListener(new ActionListener<Action>() {
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                switch(actionEvent.getActionId()) {
+                    case HIDDEN:
+                        stop();
+                        break;
+                        
+                    case VISIBLE:
+                        start();
+                        break;
+                        
+                    default:
+                        throw new NotImplementedException("unknown event: " + actionEvent.getActionId());
+                }
+            }
+        });
+    }
+    
+    // for testing
+    VMCollector getCollector() {
+        return collector;
+    };
+    
+    Map<String, Payload> getRegions() {
+        return regions;
+    }
+    
+    private Scale normalizeScale(long min, long max) {
+        // FIXME: this is very dumb and very inefficient
+        // needs cleanup
+        Scale minScale = Scale.getScale(min);
+        Scale maxScale = Scale.getScale(max);
+        
+        Scale[] scales = Scale.values();
+        int maxID = 0;
+        int minID = 0;
+        for (int i = 0; i < scales.length; i++) {
+            if (scales[i] == minScale) {
+                minID = i;
+            }
+            if (scales[i] == maxScale) {
+                maxID = i;
+            }
+        }
+        while (maxID - minID >= 2) {
+            minID++;
+        }
+        return scales[minID];
+    }
+    
+    private void start() {
+        timer.start();
+    }
+
+    private void stop() {
+        timer.stop();
+    }
+
+    @Override
+    public String getLocalizedName() {
+        Translate<LocaleResources> t = LocaleResources.createLocalizer();
+        return t.localize(LocaleResources.VM_INFO_TAB_MEMORY);
+    }
+
+    @Override
+    public UIComponent getView() {
+        return (UIComponent) view;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/MemoryStatsService.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.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.dao.VmMemoryStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+
+public class MemoryStatsService implements VmInformationService {
+    
+    private VmFilter filter = new AlwaysMatchFilter();
+
+    private VmMemoryStatDAO vmMemoryStatDao;
+
+    public MemoryStatsService(VmMemoryStatDAO vmMemoryStatDao) {
+        this.vmMemoryStatDao = vmMemoryStatDao;
+    }
+    
+    @Override
+    public VmInformationServiceController getInformationServiceController(VmRef ref) {
+        MemoryStatsViewProvider viewProvider = OSGIUtils.getInstance().getService(MemoryStatsViewProvider.class);
+        return new MemoryStatsController(vmMemoryStatDao, ref, viewProvider);
+    }
+
+    @Override
+    public VmFilter getFilter() {
+        return filter;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/MemoryStatsView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,48 @@
+/*
+ * 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.stats.memory.core;
+
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.core.views.UIComponent;
+
+public abstract class MemoryStatsView extends BasicView implements UIComponent {
+    
+    public abstract void addRegion(Payload region);
+    public abstract void updateRegion(Payload region);
+    
+    public abstract void requestRepaint();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/MemoryStatsViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.stats.memory.core;
+
+import com.redhat.thermostat.client.core.views.ViewProvider;
+
+public interface MemoryStatsViewProvider extends ViewProvider {
+
+    @Override
+    public MemoryStatsView createView();
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/Payload.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,145 @@
+/*
+ * 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.stats.memory.core;
+
+import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
+
+public class Payload implements Cloneable {
+
+    private String name;
+    private String tooltip;
+    
+    private double capacity;
+    private double maxCapacity;
+    private double maxUsed;
+    private double used;
+    
+    private Scale usedUnit;
+    private Scale capacityUnit;
+    
+    private StatsModel model;
+    
+    public void setModel(StatsModel model) {
+        this.model = model;
+    }
+    
+    public StatsModel getModel() {
+        return model;
+    }
+    
+    public void setCapacityUnit(Scale capacityUnit) {
+        this.capacityUnit = capacityUnit;
+    }
+    
+    public Scale getCapacityUnit() {
+        return capacityUnit;
+    }
+    
+    public void setUsedUnit(Scale usedUnit) {
+        this.usedUnit = usedUnit;
+    }
+    
+    public Scale getUsedUnit() {
+        return usedUnit;
+    }
+    
+    public double getMaxCapacity() {
+        return maxCapacity;
+    }
+    
+    public void setMaxCapacity(double maxCapacity) {
+        this.maxCapacity = maxCapacity;
+    }
+    
+    public double getUsed() {
+        return used;
+    }
+    
+    public void setUsed(double used) {
+        this.used = used;
+    }
+    
+    public double getMaxUsed() {
+        return maxUsed;
+    }
+    
+    public void setMaxUsed(double maxUsed) {
+        this.maxUsed = maxUsed;
+    }
+    
+    public double getCapacity() {
+        return capacity;
+    }
+    
+    public void setCapacity(double capacity) {
+        this.capacity = capacity;
+    }
+    
+    public String getName() {
+        return name;
+    }
+    
+    public void setName(String name) {
+        this.name = name;
+    }
+    
+    public String getTooltip() {
+        return tooltip;
+    }
+    
+    public void setTooltip(String tooltip) {
+        this.tooltip = tooltip;
+    }
+    
+    @Override
+    protected Payload clone() {
+        
+        Payload copy = new Payload();
+        
+        copy.used = used;
+        copy.capacity = capacity;
+        copy.capacityUnit = capacityUnit;
+        copy.maxCapacity = maxCapacity;
+        copy.maxUsed = maxUsed;
+        copy.model = model.clone();
+        copy.name = name;
+        copy.tooltip = tooltip;
+        copy.usedUnit = usedUnit;
+        
+        return copy;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/RangeModel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,93 @@
+/*
+ * 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.stats.memory.core;
+
+public class RangeModel {
+
+    private int minNormalized;
+    private double min;
+    
+    private int maxNormalized;
+    private double max;
+ 
+    private double value;
+ 
+    public double getMinimum() {
+        return min;
+    }
+
+    public void setMinimum(double newMinimum) {
+        this.min = newMinimum;
+    }
+
+    public double getMaximum() {
+        return max;
+    }
+
+    public void setMaximum(double newMaximum) {
+        this.max = newMaximum;
+    }
+
+    public void setMaxNormalized(int maxNormalized) {
+        this.maxNormalized = maxNormalized;
+    }
+    
+    public void setMinNormalized(int minNormalized) {
+        this.minNormalized = minNormalized;
+    }
+    
+    public double getValue() {
+        return value;
+    }
+
+    public void setValue(double newValue) {
+        this.value = newValue;
+    }
+    
+    int getMaxNormalized() {
+        return maxNormalized;
+    }
+    
+    int getMinNormalized() {
+        return minNormalized;
+    }
+    
+    public int getValueNormalized() {
+        double normalized = ((value - min) * (maxNormalized - minNormalized)/(max - min)) + minNormalized;
+        return (int) Math.round(normalized);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/StatsModel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,181 @@
+/*
+ * 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.stats.memory.core;
+
+import java.awt.Graphics2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.util.Date;
+
+import javax.swing.plaf.ColorUIResource;
+
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.DateAxis;
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
+import org.jfree.data.time.Millisecond;
+import org.jfree.data.time.TimeSeries;
+import org.jfree.data.time.TimeSeriesCollection;
+import org.jfree.data.xy.XYDataset;
+import org.jfree.ui.RectangleInsets;
+
+public class StatsModel implements Cloneable {
+
+    private static final String lock = new String("MemoryStatsModelLock");
+
+    private String name;
+    
+    private TimeSeries dataSet;
+    
+    public StatsModel() {
+        dataSet = new TimeSeries("");
+    }
+    
+    BufferedImage getChart(int width, int height, ColorUIResource bgColor, ColorUIResource fgColor) {
+        JFreeChart chart = createChart(bgColor, fgColor);
+        
+        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+        chart.draw((Graphics2D) image.getGraphics(), new Rectangle2D.Double(0, 0, width, height), null);
+        
+        return image;
+    }
+    
+    public String getName() {
+        return name;
+    }
+    
+    public void setName(String name) {
+        dataSet.setDescription(name);
+        this.name = name;
+    }
+    
+    public void setRange(int seconds) {
+        dataSet.setMaximumItemCount(seconds);
+    }
+    
+    public void addData(long timestamp, double value) {
+        Millisecond millisecond = new Millisecond(new Date(timestamp));
+        synchronized (lock) {
+            if (dataSet.getValue(millisecond) == null) {
+                dataSet.add(millisecond, value);
+                dataSet.removeAgedItems(true);
+            }
+        }
+    }
+    
+    @Override
+    protected StatsModel clone() {
+        
+        StatsModel model = new StatsModel();
+        model.setName(name);
+        model.setRange(dataSet.getMaximumItemCount());
+        
+        try {
+            model.dataSet = dataSet.createCopy(0, dataSet.getItemCount() - 1);
+        } catch (CloneNotSupportedException e) {
+            // ah... it's supported here...
+            e.printStackTrace();
+        }
+        
+        return model;
+    }
+    
+    /**
+     * Creates a chart.
+     *
+     * @return a chart.
+     */
+    private JFreeChart createChart(ColorUIResource bgColor, ColorUIResource fgColor) {
+
+        XYDataset priceData = null;
+        synchronized (lock) {            
+            try {
+                priceData = new TimeSeriesCollection(dataSet.createCopy(0,
+                                                     dataSet.getItemCount() - 1));
+            } catch (CloneNotSupportedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        XYPlot plot = new XYPlot();
+        
+        plot.setDomainGridlinesVisible(false);
+        plot.setDomainCrosshairVisible(false);
+        plot.setRangeGridlinesVisible(false);
+        plot.setRangeCrosshairVisible(false);
+                
+        DateAxis dateAxis = new DateAxis();
+        
+        dateAxis.setTickLabelsVisible(false);
+        dateAxis.setTickMarksVisible(false);
+        dateAxis.setAxisLineVisible(false);
+        dateAxis.setNegativeArrowVisible(false);
+        dateAxis.setPositiveArrowVisible(false);
+        dateAxis.setVisible(false);
+        
+        NumberAxis numberAxis = new NumberAxis();
+        numberAxis.setTickLabelsVisible(false);
+        numberAxis.setTickMarksVisible(false);
+        numberAxis.setAxisLineVisible(false);
+        numberAxis.setNegativeArrowVisible(false);
+        numberAxis.setPositiveArrowVisible(false);
+        numberAxis.setVisible(false);
+        numberAxis.setAutoRangeIncludesZero(false);
+        
+        plot.setDomainAxis(dateAxis);
+        plot.setRangeAxis(numberAxis);
+        plot.setDataset(priceData);
+        
+        plot.setInsets(new RectangleInsets(-1, -1, 0, 0));
+        
+        plot.setRenderer(new StandardXYItemRenderer(StandardXYItemRenderer.LINES));
+        plot.setBackgroundPaint(bgColor);
+        
+        JFreeChart chart = new JFreeChart(null, JFreeChart.DEFAULT_TITLE_FONT, plot, false);
+        
+        plot.getRenderer().setSeriesPaint(0, fgColor);
+        chart.setAntiAlias(true);
+        chart.setBorderVisible(false);
+        
+        return chart;
+    }
+    
+    TimeSeries getDataSet() {
+        return dataSet;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/locale/LocaleResources.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,52 @@
+/*
+ * 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.stats.memory.core.locale;
+
+import com.redhat.thermostat.common.locale.Translate;
+
+public enum LocaleResources {
+
+    VM_INFO_TAB_MEMORY,
+    RESOURCE_MISSING;
+    
+    public static final String RESOURCE_BUNDLE =
+            "com.redhat.thermostat.client.stats.memory.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/client/memory-stats-panel/core/src/main/resources/com/redhat/thermostat/client/stats/memory/locale/strings.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,2 @@
+RESOURCE_MISSING = Missing translation!
+VM_INFO_TAB_MEMORY = Memory
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/test/java/com/redhat/thermostat/client/stats/memory/core/MemoryStatsControllerTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,269 @@
+/*
+ * 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.stats.memory.core;
+
+import static org.junit.Assert.assertEquals;
+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.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.List;
+import java.util.Map;
+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.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.Timer.SchedulingType;
+import com.redhat.thermostat.common.TimerFactory;
+import com.redhat.thermostat.common.appctx.ApplicationContext;
+import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
+import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.model.VmMemoryStat;
+import com.redhat.thermostat.common.model.VmMemoryStat.Generation;
+import com.redhat.thermostat.common.model.VmMemoryStat.Space;
+
+public class MemoryStatsControllerTest {
+
+    private Generation[] generations = new Generation[2];
+    
+    private VmMemoryStatDAO memoryStatDao;
+    private MemoryStatsView view;
+    private Timer timer;
+    
+    private ActionListener<MemoryStatsView.Action> viewListener;
+    
+    private MemoryStatsController controller;
+    
+    private Space canary;
+
+    
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Before
+    public void setUp() {
+        timer = mock(Timer.class);
+        ArgumentCaptor<Runnable> actionCaptor = ArgumentCaptor.forClass(Runnable.class);
+        doNothing().when(timer).setAction(actionCaptor.capture());
+        
+        TimerFactory timerFactory = mock(TimerFactory.class);
+        when(timerFactory.createTimer()).thenReturn(timer);
+        ApplicationContext.getInstance().setTimerFactory(timerFactory);
+        
+        List<VmMemoryStat> vmInfo = new ArrayList<>();
+        
+        for (int i = 0; i < 2; i++) {
+            Generation generation = new Generation();
+            generation.setName("fluff" + i);
+            VmMemoryStat.Space[] spaces = new VmMemoryStat.Space[2 + (1 - i)]; 
+            for (int j = 0; j < 2; j++) {
+                Space space = new Space();
+                space.setName("fluffer" + i + j);
+                space.setUsed(100);
+                space.setCapacity(1000);
+                space.setMaxCapacity(10000);
+                spaces[j] = space;
+            }
+            if (i == 0) {
+                // special payload because the others have all the same values
+                canary = new Space();
+                canary.setName("canary");
+                canary.setUsed(1);
+                canary.setCapacity(2);
+                canary.setMaxCapacity(3);
+                spaces[2] = canary;
+            }
+            generation.setSpaces(spaces);
+            generations[i] = generation;
+        }
+        
+        long timestamp = 1;
+        int vmID = 1;
+        for (int i = 0; i < 5; i++) {
+            VmMemoryStat vmMemory = new VmMemoryStat(timestamp++, vmID, generations);
+            vmInfo.add(vmMemory);
+        }
+        
+        memoryStatDao = mock(VmMemoryStatDAO.class);
+        when(memoryStatDao.getLatestVmMemoryStats(any(VmRef.class), anyLong())).thenReturn(vmInfo);
+        
+        view = mock(MemoryStatsView.class);
+        MemoryStatsViewProvider viewProvider = mock(MemoryStatsViewProvider.class);
+        when(viewProvider.createView()).thenReturn(view);
+        
+        ArgumentCaptor<ActionListener> viewArgumentCaptor =
+                ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addActionListener(viewArgumentCaptor.capture());
+
+        VmRef ref = mock(VmRef.class);
+        
+        controller = new MemoryStatsController(memoryStatDao, ref, viewProvider);
+        
+        viewListener = viewArgumentCaptor.getValue();
+    }
+    
+    @Test
+    public void testStartStopTimer() {
+        viewListener.actionPerformed(new ActionEvent<>(view, MemoryStatsView.Action.VISIBLE));
+
+        verify(timer).start();
+        verify(timer).setSchedulingType(SchedulingType.FIXED_RATE);
+
+        viewListener.actionPerformed(new ActionEvent<>(view, MemoryStatsView.Action.HIDDEN));
+
+        verify(timer).stop();
+    }
+
+    @Test
+    public void testPayloadContainSpaces() {
+        MemoryStatsController.VMCollector collettor = controller.getCollector();
+        collettor.run();
+        
+        Map<String, Payload> regions = controller.getRegions();
+        assertEquals(5, regions.size());
+        
+        assertTrue(regions.containsKey("fluffer00"));
+        assertTrue(regions.containsKey("fluffer01"));
+        assertTrue(regions.containsKey("fluffer10"));
+        assertTrue(regions.containsKey("fluffer11"));
+        
+        assertTrue(regions.containsKey("canary"));
+    }
+    
+    @Test
+    public void testValues() {
+        MemoryStatsController.VMCollector collettor = controller.getCollector();
+        collettor.run();
+        
+        Map<String, Payload> regions = controller.getRegions();
+
+        Payload payload = regions.get("fluffer00");
+        assertEquals("fluffer00", payload.getName());
+        assertEquals(10000, payload.getMaxCapacity(), 0);
+        assertEquals(1000, payload.getCapacity(), 0);
+        assertEquals(100, payload.getUsed(), 0);
+        
+        payload = regions.get("canary");
+        assertEquals("canary", payload.getName());
+        assertEquals(3, payload.getMaxCapacity(), 0);
+        assertEquals(2, payload.getCapacity(), 0);
+        assertEquals(1, payload.getUsed(), 0);
+        
+        // the value above all ensure the same scale is used
+        String tooltip = payload.getName() + ": used: " + payload.getUsed() + " " +
+                         payload.getUsedUnit() + ", capacity: " +
+                         payload.getCapacity() + " " + payload.getUsedUnit() +
+                         ", max capacity: " + payload.getMaxCapacity() + " " +
+                         payload.getUsedUnit();
+        
+        assertEquals(tooltip, payload.getTooltip());
+    }
+    
+
+    @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(memoryStatDao.getLatestVmMemoryStats(isA(VmRef.class), anyLong())).thenReturn(Arrays.asList(stat));
+
+        Runnable timerAction = controller.getCollector();
+
+        timerAction.run();
+        timerAction.run();
+
+        verify(memoryStatDao, 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);
+
+        Runnable timerAction = controller.getCollector();
+
+        timerAction.run();
+        timerAction.run();
+
+        verify(memoryStatDao, 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);
+    }
+
+    @After
+    public void tearDown() {
+        ApplicationContextUtil.resetApplicationContext();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/test/java/com/redhat/thermostat/client/stats/memory/core/PayloadTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,82 @@
+/*
+ * 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.stats.memory.core;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
+
+public class PayloadTest {
+
+    @Test
+    public void testClone() {
+        
+        StatsModel model = new StatsModel();
+        model.setName("fluffModel");
+        model.setRange(100);
+        model.addData(500, 2.0);
+        model.addData(501, 2.1);
+        
+        Payload source = new Payload();
+        source.setCapacity(10.0);
+        source.setName("fluff");
+        source.setCapacityUnit(Scale.GiB);
+        source.setMaxCapacity(100.0);
+        source.setMaxUsed(5.0);
+        source.setUsed(3.0);
+        source.setUsedUnit(Scale.MiB);
+        source.setModel(model);
+        source.setTooltip("fluffTooltip");
+        
+        Payload cloned = source.clone();
+        assertNotSame(cloned, source);
+        
+        assertEquals(source.getName(), cloned.getName());
+        assertEquals(source.getCapacity(), cloned.getCapacity(), 0);
+        assertEquals(source.getCapacityUnit(), cloned.getCapacityUnit());
+        assertEquals(source.getMaxCapacity(), cloned.getMaxCapacity(), 0);
+        assertEquals(source.getMaxUsed(), cloned.getMaxUsed(), 0);
+        assertEquals(source.getTooltip(), cloned.getTooltip());
+        assertEquals(source.getUsed(), cloned.getUsed(), 0);
+        assertEquals(source.getUsedUnit(), cloned.getUsedUnit());
+        assertNotSame(source.getModel(), cloned.getModel());
+
+        assertEquals(source.getModel().getName(), cloned.getModel().getName());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/test/java/com/redhat/thermostat/client/stats/memory/core/RangeModelTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,123 @@
+/*
+ * 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.stats.memory.core;
+
+import static org.junit.Assert.*;
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+public class RangeModelTest {
+
+    @Test
+    public void testSameRange() {
+        RangeModel model = new RangeModel();
+        
+        model.setMaximum(10);
+        model.setMinimum(0);
+        model.setValue(5);
+        
+        model.setMaxNormalized(10);
+        model.setMinNormalized(0);
+        
+        
+        Assert.assertEquals((int) model.getValue(), model.getValueNormalized());
+    }
+
+    @Test
+    public void testDoubleRange() {
+        RangeModel model = new RangeModel();
+        
+        model.setMaximum(10);
+        model.setMinimum(0);
+        model.setValue(5);
+        
+        model.setMaxNormalized(20);
+        model.setMinNormalized(0);
+        
+        
+        Assert.assertEquals(10, model.getValueNormalized());
+    }
+    
+    @Test
+    public void testRanges() {
+        RangeModel model = new RangeModel();
+        
+        model.setMaximum(10);
+        model.setMinimum(0);
+        model.setValue(5);
+        
+        model.setMaxNormalized(40);
+        model.setMinNormalized(0);
+                
+        Assert.assertEquals(20, model.getValueNormalized());
+        
+        model.setMaxNormalized(60);
+        model.setMinNormalized(0);
+                
+        Assert.assertEquals(30, model.getValueNormalized());
+                
+        model.setMaxNormalized(200);
+        model.setMinNormalized(100);
+                
+        Assert.assertEquals(150, model.getValueNormalized());
+        
+        model.setMaximum(100);
+        model.setMinimum(0);
+        model.setValue(50);
+        
+        model.setMaxNormalized(1);
+        model.setMinNormalized(0);
+                
+        Assert.assertEquals(1, model.getValueNormalized());
+        
+        model.setValue(49);
+        Assert.assertEquals(0, model.getValueNormalized());
+        
+        model.setMaximum(1.0);
+        model.setMinimum(0.0);
+        model.setValue(0.5);
+        
+        model.setMaxNormalized(100);
+        model.setMinNormalized(0);
+        
+        Assert.assertEquals(50, model.getValueNormalized());
+        
+        model.setValue(0.72);
+        Assert.assertEquals(72, model.getValueNormalized());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/test/java/com/redhat/thermostat/client/stats/memory/core/StatsModelTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.stats.memory.core;
+
+import static org.junit.Assert.*;
+
+import org.jfree.data.time.TimeSeries;
+import org.junit.Test;
+
+public class StatsModelTest {
+
+    @Test
+    public void testClone() {
+        
+        StatsModel source = new StatsModel();
+        source.setName("fluffModel");
+        source.setRange(100);
+        source.addData(500, 2.0);
+        source.addData(501, 2.1);
+        
+        StatsModel cloned = source.clone();
+        
+        assertNotSame(cloned, source);
+        
+        assertEquals(source.getName(), cloned.getName());
+     
+        assertNotSame(cloned.getDataSet(), source.getDataSet());
+        
+        for (Object series : cloned.getDataSet().getItems()) {
+            assertTrue(source.getDataSet().getItems().contains(series));
+        }
+        
+        assertEquals(cloned.getDataSet().getItemCount(),
+                     source.getDataSet().getItemCount());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/test/java/com/redhat/thermostat/client/stats/memory/core/locale/TranslateTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.core.locale;
+
+import java.io.IOException;
+import java.util.Locale;
+import java.util.Properties;
+
+import junit.framework.Assert;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.client.stats.memory.core.locale.LocaleResources;
+import com.redhat.thermostat.common.locale.Translate;
+
+public class TranslateTest {
+
+    private Locale lang;
+
+    @Before
+    public void setUp() {
+        this.lang = Locale.getDefault();
+        Locale.setDefault(Locale.US);
+    }
+
+    @After
+    public void tearDown() {
+        Locale.setDefault(lang);
+    }
+
+    @Test
+    public void verifyTranslationsAreThere() 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());
+        Translate<LocaleResources> t = LocaleResources.createLocalizer();
+        Assert.assertEquals("Missing translation!", t.localize(LocaleResources.RESOURCE_MISSING));
+        Assert.assertEquals("Memory", t.localize(LocaleResources.VM_INFO_TAB_MEMORY));
+    }
+}
--- a/client/memory-stats-panel/pom.xml	Fri Oct 26 13:13:42 2012 +0200
+++ b/client/memory-stats-panel/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -1,81 +1,58 @@
 <?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>
-    <groupId>com.redhat.thermostat</groupId>
     <version>0.5.0-SNAPSHOT</version>
   </parent>
+
   <artifactId>thermostat-osgi-memory-stats-panel</artifactId>
-  <packaging>bundle</packaging>
+  <packaging>pom</packaging>
+
   <name>Thermostat Client VM Memory Monitor plugin</name>
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <configuration>
-          <instructions>
-            <Private-Package>
-            	com.redhat.thermostat.client.stats.memory,
-         		com.redhat.thermostat.client.stats.memory.locale,
-            </Private-Package>
-            <Bundle-Activator>com.redhat.thermostat.client.stats.memory.MemoryStatsPanelActivator</Bundle-Activator>
-            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
-            <Bundle-SymbolicName>com.redhat.thermostat.client.stats.memory</Bundle-SymbolicName>
-            <!-- 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>org.jfree</groupId>
-      <artifactId>jfreechart</artifactId>
-    </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>
-  </dependencies>
+  <modules>
+    <module>core</module>
+    <module>swing</module>
+  </modules>
+
 </project>
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryGraphPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +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.stats.memory;
-
-import java.awt.Dimension;
-import java.beans.Transient;
-
-import javax.swing.BoxLayout;
-import javax.swing.JPanel;
-
-@SuppressWarnings("serial")
-class MemoryGraphPanel extends JPanel {
-
-    private MemoryMeter meter;
-    
-    /**
-     * Create the panel.
-     */
-    public MemoryGraphPanel() {
-        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
-        meter = new MemoryMeter();
-        add(meter);
-    }
-    
-    public void setMemoryGraphProperties(Payload region) {
-
-        meter.getPrimaryModel().setMinimum(0);
-        meter.getPrimaryModel().setMaximum(region.getMaxUsed());
-        meter.getPrimaryModel().setValue(region.getUsed());
-        
-        meter.getSecondaryModel().setMinimum(0);
-        meter.getSecondaryModel().setMaximum(region.getMaxCapacity());
-        meter.getSecondaryModel().setValue(region.getCapacity());
-        
-        meter.setToolTipText(region.getTooltip());
-        
-        meter.setPrimaryScaleUnit(region.getUsedUnit().toString());
-        meter.setSecondayScaleUnit(region.getCapacityUnit().toString());
-        
-        meter.setStats(region.getModel());
-    }
-    
-    @Override
-    @Transient
-    public Dimension getPreferredSize() {
-        return meter.getPreferredSize();
-    }
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryMeter.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,433 +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.stats.memory;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.FontMetrics;
-import java.awt.GradientPaint;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Insets;
-import java.awt.Paint;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.geom.Rectangle2D;
-import java.awt.geom.RoundRectangle2D;
-import java.awt.image.BufferedImage;
-import java.beans.Transient;
-
-import javax.swing.JComponent;
-import javax.swing.plaf.ColorUIResource;
-
-import sun.swing.SwingUtilities2;
-
-@SuppressWarnings({ "restriction", "serial" })
-public class MemoryMeter extends JComponent {
-    
-    // TODO the font should be customizable
-    private static final Font font = new Font("SansSerif", Font.PLAIN, 10);
-    
-    private static final int TICK_NUM = 100;
-    private static final int SMALL_TICK_NUM = 5;
-    
-    private static final int MAIN_BAR_HEIGHT = 20;
-    
-    private static final ColorUIResource MAIN_GRADIENT_TOP = new ColorUIResource(0xf1f3f1);
-    private static final ColorUIResource MAIN_BORDER_COLOR = new ColorUIResource(0xa8aca8);
-    
-    private static final ColorUIResource MAIN_BAR_BASE_COLOR_TOP = new ColorUIResource(0xbcd5ef);
-    private static final ColorUIResource MAIN_BAR_BASE_COLOR = new ColorUIResource(0x4A90D9);
-    
-    //private static final ColorUIResource STATS_BG = new ColorUIResource(0xF8F8F8);
-    private static final ColorUIResource STATS_BG = new ColorUIResource(0xFFFFFF);
-    
-    private ColorUIResource tickColor;
-    
-    private RangeModel primary;
-    private RangeModel secondary;
-    
-    private Insets boundInsets;
-    
-    private RangeModel internalSecondaryModel;
-    
-    private StatsModel primaryStats;
-    
-    private String primaryUnit;
-    private String secondaryUnit;
-
-        public void setPrimaryScaleUnit(String primaryUnit) {
-        this.primaryUnit = primaryUnit;
-    }
-    
-    public void setSecondayScaleUnit(String secondaryUnit) {
-        this.secondaryUnit = secondaryUnit;
-    }
-    
-    public StatsModel getStats() {
-        return primaryStats;
-    }
-    
-    public void setStats(StatsModel primaryStats) {
-        this.primaryStats = primaryStats;
-    }
-
-    public MemoryMeter() {
-        
-        secondaryUnit = "";
-        primaryUnit = "";
-        
-        boundInsets = new Insets(10, 10, 20, 20);
-        
-        tickColor = new ColorUIResource(0xdbdddb);
-        
-        primary = new RangeModel();
-        primary.setMinimum(0);
-        primary.setMaximum(100);
-        primary.setMinNormalized(0);
-        primary.setMaxNormalized(100);
-        
-        secondary = new RangeModel();
-        secondary.setMinimum(0);
-        secondary.setMaximum(100);
-        secondary.setMinNormalized(0);
-        secondary.setMaxNormalized(100);
-        
-        internalSecondaryModel = new RangeModel();
-    }
-    
-    public ColorUIResource getTickColor() {
-        return tickColor;
-    }
-    
-    public void setTickColor(ColorUIResource tickColor) {
-        this.tickColor = tickColor;
-    }
-    
-    public RangeModel getPrimaryModel() {
-        return primary;
-    }
-    
-    public RangeModel getSecondaryModel() {
-        return secondary;
-    }
-    
-    protected Rectangle getOuterBounds() {
-        return new Rectangle(0, 0, getWidth(), getHeight());
-    }
-    
-    protected Rectangle getBoundsWithInsets(Rectangle bounds) {
-        return new Rectangle(bounds.x + boundInsets.left,
-                             bounds.y + boundInsets.top,
-                             bounds.width  - boundInsets.right,
-                             bounds.height - boundInsets.bottom);
-    }
-        
-    /**
-     * paint the outher frame, including the light border sorrounding
-     */
-    protected void paintOuterFrame(Graphics2D graphics, Rectangle bounds) {
-
-        RoundRectangle2D frame = new RoundRectangle2D.Float(bounds.x, bounds.y, bounds.width, bounds.height, 6, 6);
-
-        Paint paint = new GradientPaint(0, 0, MAIN_GRADIENT_TOP, 0, getHeight(), getBackground());
-        graphics.setPaint(paint);
-        graphics.fill(frame);
-        
-        paint = new GradientPaint(0, 0, MAIN_BORDER_COLOR, 0, getHeight(), getBackground());
-        graphics.setPaint(paint);
-        frame = new RoundRectangle2D.Float(bounds.x, bounds.y, bounds.width -1, bounds.height, 6, 6);
-        graphics.draw(frame);
-    }
-    
-    /**
-     * paint the track sorrounding the main bar
-     */
-    protected void paintMainBarTrackFill(Graphics2D graphics, Rectangle bounds) {
-        
-        Paint paint = new GradientPaint(0, 0, MAIN_GRADIENT_TOP, 0, bounds.height, Color.WHITE);
-        graphics.setPaint(paint);
-        RoundRectangle2D frame = new RoundRectangle2D.Float(0, 0, bounds.width, bounds.height, 6, 6);
-        graphics.fill(frame);
-    }
-    
-    /**
-     */
-    protected void paintMainBarTrackBorder(Graphics2D graphics, Rectangle bounds) {
-        Paint paint = new GradientPaint(0, 0, MAIN_BORDER_COLOR, getWidth(), 0, getBackground());
-        graphics.setPaint(paint);
-        
-        RoundRectangle2D frame = new RoundRectangle2D.Float(0, 0, bounds.width - 1, bounds.height, 6, 6);
-        graphics.draw(frame);
-    }
-
-    
-    /**
-     * this is the main bar, will it up to what is defined by the model
-     */
-    protected void paintMainBarFill(Graphics2D graphics, Rectangle bounds) {
-        Paint paint = new GradientPaint(0, 0, MAIN_BAR_BASE_COLOR, getWidth() * 2, 0, getBackground());
-        graphics.setPaint(paint);
-        
-        RoundRectangle2D frame =
-                new RoundRectangle2D.Float(0, 0, getPrimaryModel().getValueNormalized(),
-                                           bounds.height, 6, 6);
-        graphics.fill(frame);
-        
-        String value = String.valueOf(getPrimaryModel().getValue()) + " " + primaryUnit;
-        Rectangle2D fontBounds = font.getStringBounds(value, graphics.getFontRenderContext());
-        int width = (int) (bounds.width/2 - fontBounds.getWidth()/2) - 1;
-        
-        if (width > getPrimaryModel().getValueNormalized()) {
-            graphics.setPaint(MAIN_BAR_BASE_COLOR);
-        } else {
-            graphics.setPaint(getBackground());
-        }
-
-        int height  = (int) (bounds.height / 2 + fontBounds.getHeight()/2);
-        SwingUtilities2.drawString(this, graphics, value, width, height);
-    }
-    
-    /**
-     */
-    private void paintMainBar(Graphics2D g, Rectangle bounds) {
-        
-        Graphics2D graphics = (Graphics2D) g.create();
-                
-        graphics.translate(bounds.x, bounds.y);
-        paintMainBarTrackFill(graphics, bounds);
-        
-        paintMainBarFill(graphics, bounds);
-        
-        paintMainBarTrackBorder(graphics, bounds);
-        graphics.dispose();
-    }
-    
-    /**
-     */
-    protected void drawBottomBar(Graphics2D g, Rectangle bounds) {
-
-        Graphics2D graphics = (Graphics2D) g.create();
-        graphics.translate(bounds.x, bounds.y + bounds.height);
-        
-        drawTickMark(graphics, bounds);
-        
-        paintSecondaryBarFill(graphics, bounds);
-        
-        graphics.dispose();
-    }
-    
-    /**
-     */
-    protected void drawTickMark(Graphics2D graphics, Rectangle bounds) {
-      
-        graphics.setPaint(MAIN_BORDER_COLOR);
-        
-        int smallTop = bounds.height - 5;
-        int smallBottom = bounds.height;
-
-        int mainTop = smallTop + 20;
-        int mainBottom = smallBottom - 15;
-      
-        // the first and last tick are always big, this is the first
-        graphics.drawLine(0, mainTop, 0, mainBottom);
-      
-        // the space between the vertical lines
-        double tickSpace = ((double) bounds.width) / TICK_NUM;
-      
-        internalSecondaryModel.setMaxNormalized(bounds.width);      
-        int numTicks = 0;
-
-        for (int x = 0; x < bounds.width; x += tickSpace + 0.5) {
-            if (numTicks % SMALL_TICK_NUM == 0) {
-              
-                graphics.drawLine(x, smallTop, x, smallBottom + 5);
-
-                internalSecondaryModel.setValue(x);
-            } else {
-                graphics.drawLine(x, smallTop, x, smallBottom);
-            }
-            numTicks++;
-        }
-        
-        // that's the last
-        graphics.drawLine(bounds.width, mainTop, bounds.width, mainBottom);
-        graphics.drawLine(0, smallTop, bounds.width, smallTop);
-        
-        drawStrings(graphics, mainBottom, mainTop, bounds.width);
-    }
-    
-    protected void drawStrings(Graphics2D graphics, int top, int bottom, int right) {
-      
-      // now draw the min/max values of both side of markers      
-      // top bar min value
-      FontMetrics fm = SwingUtilities2.getFontMetrics(this, font);
-      
-      String value = String.valueOf(getPrimaryModel().getMinimum()) + " " + primaryUnit;
-      int height = top + fm.getAscent()/2;
-      SwingUtilities2.drawString(this, graphics, value, 1, height);
-      
-      value = String.valueOf(getSecondaryModel().getMinimum()) + " " + secondaryUnit;
-      height = bottom;
-      SwingUtilities2.drawString(this, graphics, value, 1, height);
-      
-      value = String.valueOf(getPrimaryModel().getMaximum()) + " " + primaryUnit;
-      height = top + fm.getAscent()/2;
-
-      int width = (int) (right - font.getStringBounds(value, graphics.getFontRenderContext()).getWidth()) - 1;
-      SwingUtilities2.drawString(this, graphics, value, width, height);
-      
-      value = String.valueOf(getSecondaryModel().getMaximum()) + " " + secondaryUnit;
-      height = bottom;
-      width = (int) (right - font.getStringBounds(value, graphics.getFontRenderContext()).getWidth()) - 1;
-      SwingUtilities2.drawString(this, graphics, value, width, height);
-      
-      // now draw the actual value for the bottom bar, the top bar is drawn in
-      // its fill method
-      value = String.valueOf(getSecondaryModel().getValue()) + " " + secondaryUnit;
-      width = right/2;
-      Rectangle2D bounds = font.getStringBounds(value, graphics.getFontRenderContext());
-      width = (int) (width - bounds.getWidth()/2) - 1;
-      SwingUtilities2.drawString(this, graphics, value, width, height);
-      RoundRectangle2D frame = new RoundRectangle2D.Double(width - 2, height - bounds.getHeight(),
-                                                          bounds.getWidth() + 4, bounds.getHeight() + 4,
-                                                          4, 4);
-      graphics.draw(frame);
-    }
-    
-    protected void paintSecondaryBarFill(Graphics2D graphics, Rectangle bounds) {
-        
-        graphics.setPaint(MAIN_BAR_BASE_COLOR_TOP);
-        graphics.drawLine(1, bounds.height, getSecondaryModel().getValueNormalized() - 1, bounds.height);
-        
-        graphics.setPaint(MAIN_BAR_BASE_COLOR);
-        graphics.fillRect(1, bounds.height + 1, getSecondaryModel().getValueNormalized(), 2);
-    }
-    
-    protected void paintStats(Graphics2D graphics, Rectangle bounds) {
-        
-        int imageWidth = bounds.width - 2;
-        if (imageWidth < 0 || bounds.height < 0) {
-            return;
-        }
-        
-        StatsModel stats = getStats();
-        drawStats(graphics, stats, bounds.x, bounds.y, imageWidth, bounds.height);
-    }
-    
-    private void drawStats(Graphics2D graphics, StatsModel stats, int x, int y, int imageWidth, int height) {
-        if (stats != null) {
-            BufferedImage image = stats.getChart(imageWidth, height, STATS_BG,
-                                                 new ColorUIResource(getForeground()));
-       
-            paintStatsLabel(graphics, image, stats.getName());
-            graphics.drawImage(image, x, y, null);
-        }
-    }
-    
-    protected void paintStatsLabel(Graphics2D graphics, BufferedImage image, String label) {
-        int height = SwingUtilities2.getFontMetrics(this, font).getAscent() + 2;
-        if (height <= 0) {
-            return;
-        }
-        
-        Graphics2D imageGraphics = (Graphics2D) image.getGraphics();
-        imageGraphics.setColor(getForeground());
-        imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-        
-        SwingUtilities2.drawString(this, imageGraphics, label, 2, height);
-    }
-    
-    @Override
-    protected void paintComponent(Graphics g) {
-
-        Graphics2D graphics = (Graphics2D) g.create();
-        graphics.setFont(font);
-        
-        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-        graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
-        
-        Rectangle outerBounds = getOuterBounds();
-        Rectangle innerBounds = getBoundsWithInsets(outerBounds);
-        Rectangle statsBound =  getBoundsWithInsets(outerBounds);
-        
-        // move the bar close to the center
-        innerBounds.height = MAIN_BAR_HEIGHT;
-        innerBounds.y = outerBounds.height/2;
-        
-        // make the stats area cover the upper portion instead
-        statsBound.height = (outerBounds.height/2) - MAIN_BAR_HEIGHT;
-        
-        resetModels(0, innerBounds.width);
-
-        // some eye candy
-        paintOuterFrame(graphics, outerBounds);
-
-        // paint the usage stats
-        paintStats(graphics, statsBound);
-        
-        // main and bottom bars
-        paintMainBar(graphics, innerBounds);
-        drawBottomBar(graphics, innerBounds);
-        
-        graphics.dispose();
-    }
-    
-    private void resetModels(int min, int max) {
-        
-        getPrimaryModel().setMaxNormalized(max);
-        getPrimaryModel().setMinNormalized(min);
-        
-        RangeModel model = getSecondaryModel();
-        model.setMaxNormalized(max);
-        model.setMinNormalized(min);
-        
-        internalSecondaryModel.setMaximum(model.getMaximum());
-        internalSecondaryModel.setMinimum(model.getMinimum());
-        internalSecondaryModel.setValue(model.getValue());
-        
-        internalSecondaryModel.setMaxNormalized(max);
-        internalSecondaryModel.setMinNormalized(0);
-    }
-    
-    @Override
-    @Transient
-    public Dimension getPreferredSize() {
-        return new Dimension(850, 150);
-    }
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsController.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,228 +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.stats.memory;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-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.stats.memory.locale.LocaleResources;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.NotImplementedException;
-import com.redhat.thermostat.common.Timer;
-import com.redhat.thermostat.common.Timer.SchedulingType;
-import com.redhat.thermostat.common.appctx.ApplicationContext;
-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.model.VmMemoryStat;
-import com.redhat.thermostat.common.model.VmMemoryStat.Generation;
-import com.redhat.thermostat.common.model.VmMemoryStat.Space;
-import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
-
-class MemoryStatsController implements VmInformationServiceController {
-
-    private final MemoryStatsView view;
-    private final VmMemoryStatDAO vmDao;
-   
-    private final VmRef ref;
-    private final Timer timer;
-    
-    private final Map<String, Payload> regions;
-    
-    private VMCollector collector;
-    
-    class VMCollector implements Runnable {
-
-        private long desiredUpdateTimeStamp = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1);
-
-        @Override
-        public void run() {
-            List<VmMemoryStat> vmInfo = vmDao.getLatestVmMemoryStats(ref, desiredUpdateTimeStamp);
-            for (VmMemoryStat memoryStats: vmInfo) {
-                Generation[] generations = memoryStats.getGenerations();
-                
-                for (Generation generation : generations) {
-                    Space[] spaces = generation.getSpaces();
-                    for (Space space: spaces) {
-                        Payload payload = regions.get(space.getName());
-                        if (payload == null) {
-                            payload = new Payload();
-                            payload.setName(space.getName());
-                        }
-
-                        Scale usedScale = normalizeScale(space.getUsed(), space.getCapacity());
-                        double used = Scale.convertTo(usedScale, space.getUsed(), 100);
-                        double maxUsed = Scale.convertTo(usedScale, space.getCapacity(), 100);
-                        
-                        payload.setUsed(used);
-                        payload.setMaxUsed(maxUsed);
-                        payload.setUsedUnit(usedScale);
-                        
-                        Scale maxScale = normalizeScale(space.getCapacity(), space.getMaxCapacity());
-                        double capacity = Scale.convertTo(maxScale, space.getCapacity(), 100);
-                        double maxCapacity = Scale.convertTo(maxScale, space.getMaxCapacity(), 100);
-                        
-                        payload.setCapacity(capacity);
-                        payload.setMaxCapacity(maxCapacity);
-                        payload.setCapacityUnit(maxScale);
-                        
-                        String tooltip = space.getName() + ": used: " + used + " " + usedScale +
-                                ", capacity: " + capacity + " " + maxScale +
-                                ", max capacity: " + maxCapacity + " " + maxScale;
-                        
-                        payload.setTooltip(tooltip);
-                        
-                        StatsModel model = payload.getModel();
-                        if (model == null) {
-                            model = new StatsModel();
-                            model.setName(space.getName());
-                            model.setRange(3600);
-                        }
-                        
-                        // normalize this always in the same unit
-                        model.addData(memoryStats.getTimeStamp(),
-                                      Scale.convertTo(Scale.MiB, space.getUsed(), 100));
-                        
-                        payload.setModel(model);
-                        if (regions.containsKey(space.getName())) {
-                            view.updateRegion(payload.clone());
-                        } else {
-                            view.addRegion(payload.clone());
-                            regions.put(space.getName(), payload);
-                        }
-                        
-                        view.requestRepaint();
-                        desiredUpdateTimeStamp = Math.max(desiredUpdateTimeStamp, memoryStats.getTimeStamp());
-                    }
-                }
-            }
-        }
-    }
-    
-    public MemoryStatsController(final VmMemoryStatDAO vmMemoryStatDao, final VmRef ref, MemoryStatsViewProvider viewProvider) {
-        
-        regions = new HashMap<>();
-        this.ref = ref;
-        vmDao = vmMemoryStatDao;
-        view = viewProvider.createView();
-        
-        timer = ApplicationContext.getInstance().getTimerFactory().createTimer();
-        
-        collector = new VMCollector();
-        timer.setAction(collector);
-        
-        timer.setInitialDelay(0);
-        timer.setDelay(1000);
-        timer.setTimeUnit(TimeUnit.MILLISECONDS);
-        timer.setSchedulingType(SchedulingType.FIXED_RATE);
-
-        view.addActionListener(new ActionListener<Action>() {
-            @Override
-            public void actionPerformed(ActionEvent<Action> actionEvent) {
-                switch(actionEvent.getActionId()) {
-                    case HIDDEN:
-                        stop();
-                        break;
-                        
-                    case VISIBLE:
-                        start();
-                        break;
-                        
-                    default:
-                        throw new NotImplementedException("unknown event: " + actionEvent.getActionId());
-                }
-            }
-        });
-    }
-    
-    // for testing
-    VMCollector getCollector() {
-        return collector;
-    };
-    
-    Map<String, Payload> getRegions() {
-        return regions;
-    }
-    
-    private Scale normalizeScale(long min, long max) {
-        // FIXME: this is very dumb and very inefficient
-        // needs cleanup
-        Scale minScale = Scale.getScale(min);
-        Scale maxScale = Scale.getScale(max);
-        
-        Scale[] scales = Scale.values();
-        int maxID = 0;
-        int minID = 0;
-        for (int i = 0; i < scales.length; i++) {
-            if (scales[i] == minScale) {
-                minID = i;
-            }
-            if (scales[i] == maxScale) {
-                maxID = i;
-            }
-        }
-        while (maxID - minID >= 2) {
-            minID++;
-        }
-        return scales[minID];
-    }
-    
-    private void start() {
-        timer.start();
-    }
-
-    private void stop() {
-        timer.stop();
-    }
-
-    @Override
-    public String getLocalizedName() {
-        Translate<LocaleResources> t = LocaleResources.createLocalizer();
-        return t.localize(LocaleResources.VM_INFO_TAB_MEMORY);
-    }
-
-    @Override
-    public UIComponent getView() {
-        return (UIComponent) view;
-    }
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsPanelActivator.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +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.stats.memory;
-
-import java.util.Map;
-
-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.osgi.service.ApplicationService;
-import com.redhat.thermostat.common.MultipleServiceTracker;
-import com.redhat.thermostat.common.MultipleServiceTracker.Action;
-import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
-
-public class MemoryStatsPanelActivator implements BundleActivator {
-
-    private MultipleServiceTracker tracker;
-    private ServiceRegistration memoryStatRegistration;
-
-    @Override
-    public void start(final BundleContext context) throws Exception {
-        MemoryStatsViewProvider provider = new SwingMemoryStatsViewProvider();
-        context.registerService(MemoryStatsViewProvider.class.getName(), provider, null);
-        
-        Class<?>[] deps = new Class<?>[] {
-            ApplicationService.class,
-            VmMemoryStatDAO.class,
-        };
-
-        tracker = new MultipleServiceTracker(context, deps, new Action() {
-            
-            @Override
-            public void dependenciesUnavailable() {
-                memoryStatRegistration.unregister();
-                memoryStatRegistration = null;
-            }
-
-            @Override
-            public void dependenciesAvailable(Map<String, Object> services) {
-                VmMemoryStatDAO memoryStatDao = (VmMemoryStatDAO) services.get(VmMemoryStatDAO.class.getName());
-                MemoryStatsService impl = new MemoryStatsService(memoryStatDao);
-                memoryStatRegistration = context.registerService(VmInformationService.class.getName(), impl , null);
-            }
-        });
-        tracker.open();
-
-    }
-
-    @Override
-    public void stop(BundleContext context) throws Exception {
-        tracker.close();
-    }
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsService.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-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.dao.VmMemoryStatDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-
-class MemoryStatsService implements VmInformationService {
-    
-    private VmFilter filter = new AlwaysMatchFilter();
-
-    private VmMemoryStatDAO vmMemoryStatDao;
-
-    public MemoryStatsService(VmMemoryStatDAO vmMemoryStatDao) {
-        this.vmMemoryStatDao = vmMemoryStatDao;
-    }
-    
-    @Override
-    public VmInformationServiceController getInformationServiceController(VmRef ref) {
-        MemoryStatsViewProvider viewProvider = OSGIUtils.getInstance().getService(MemoryStatsViewProvider.class);
-        return new MemoryStatsController(vmMemoryStatDao, ref, viewProvider);
-    }
-
-    @Override
-    public VmFilter getFilter() {
-        return filter;
-    }
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsView.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.core.views.UIComponent;
-
-public abstract class MemoryStatsView extends BasicView implements UIComponent {
-    
-    public abstract void addRegion(Payload region);
-    public abstract void updateRegion(Payload region);
-    
-    public abstract void requestRepaint();
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsViewImpl.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,152 +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.stats.memory;
-
-import java.awt.Component;
-import java.awt.Dimension;
-import java.beans.Transient;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.swing.Box;
-import javax.swing.BoxLayout;
-import javax.swing.JPanel;
-import javax.swing.SwingUtilities;
-
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.ui.ComponentVisibleListener;
-import com.redhat.thermostat.client.ui.SwingComponent;
-import com.redhat.thermostat.swing.HeaderPanel;
-
-public class MemoryStatsViewImpl extends MemoryStatsView implements SwingComponent {
-
-    private static final long REPAINT_DELAY = 500;
-    private long lastRepaint;
-    
-    private HeaderPanel visiblePanel;
-    private JPanel realPanel;
-    
-    private final Map<String, MemoryGraphPanel> regions;
-    
-    private Dimension preferredSize;
-    
-    public MemoryStatsViewImpl() {
-        super();
-        visiblePanel = new HeaderPanel();
-        regions = new HashMap<>();
- 
-        preferredSize = new Dimension(0, 0);
-        
-        visiblePanel.setHeader("Memory Regions");
-
-        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
-            @Override
-            public void componentShown(Component component) {
-                notifier.fireAction(Action.VISIBLE);
-            }
-
-            @Override
-            public void componentHidden(Component component) {
-                notifier.fireAction(Action.HIDDEN);
-            }
-        });
-
-        realPanel = new JPanel();
-        realPanel.setLayout(new BoxLayout(realPanel, BoxLayout.Y_AXIS));
-        visiblePanel.setContent(realPanel);
-    }
-    
-    @Transient
-    public Dimension getPreferredSize() {
-        return new Dimension(preferredSize);
-    }
-    
-    @Override
-    public void updateRegion(final Payload region) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                MemoryGraphPanel memoryGraphPanel = regions.get(region.getName());
-                memoryGraphPanel.setMemoryGraphProperties(region);
-            }
-        });
-    }
-    
-    @Override
-    public void addRegion(final Payload region) {
-
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                MemoryGraphPanel memoryGraphPanel = new MemoryGraphPanel();
-                
-                realPanel.add(memoryGraphPanel);
-                realPanel.add(Box.createRigidArea(new Dimension(5,5)));
-                regions.put(region.getName(), memoryGraphPanel);
-                
-                // components are stacked up vertically in this panel
-                Dimension memoryGraphPanelMinSize = memoryGraphPanel.getMinimumSize();
-                preferredSize.height += memoryGraphPanelMinSize.height + 5;
-                if (preferredSize.width < (memoryGraphPanelMinSize.width + 5)) {
-                    preferredSize.width = memoryGraphPanelMinSize.width + 5;
-                }
-
-                updateRegion(region);
-                realPanel.revalidate();
-            }
-        });
-    }
-
-    @Override
-    public Component getUiComponent() {
-        return visiblePanel;
-    }
-
-    @Override
-    public void requestRepaint() {
-        // really only repaint every REPAINT_DELAY milliseconds
-        long now = System.currentTimeMillis();
-        if (now - lastRepaint > REPAINT_DELAY) {
-            visiblePanel.repaint();
-            lastRepaint = System.currentTimeMillis();
-        }
-    }
-    
-    public BasicView getView() {
-        return this;
-    }
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.stats.memory;
-
-import com.redhat.thermostat.client.core.views.ViewProvider;
-
-public interface MemoryStatsViewProvider extends ViewProvider {
-
-    @Override
-    public MemoryStatsView createView();
-    
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/Payload.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,145 +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.stats.memory;
-
-import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
-
-public class Payload implements Cloneable {
-
-    private String name;
-    private String tooltip;
-    
-    private double capacity;
-    private double maxCapacity;
-    private double maxUsed;
-    private double used;
-    
-    private Scale usedUnit;
-    private Scale capacityUnit;
-    
-    private StatsModel model;
-    
-    public void setModel(StatsModel model) {
-        this.model = model;
-    }
-    
-    public StatsModel getModel() {
-        return model;
-    }
-    
-    public void setCapacityUnit(Scale capacityUnit) {
-        this.capacityUnit = capacityUnit;
-    }
-    
-    public Scale getCapacityUnit() {
-        return capacityUnit;
-    }
-    
-    public void setUsedUnit(Scale usedUnit) {
-        this.usedUnit = usedUnit;
-    }
-    
-    public Scale getUsedUnit() {
-        return usedUnit;
-    }
-    
-    public double getMaxCapacity() {
-        return maxCapacity;
-    }
-    
-    public void setMaxCapacity(double maxCapacity) {
-        this.maxCapacity = maxCapacity;
-    }
-    
-    public double getUsed() {
-        return used;
-    }
-    
-    public void setUsed(double used) {
-        this.used = used;
-    }
-    
-    public double getMaxUsed() {
-        return maxUsed;
-    }
-    
-    public void setMaxUsed(double maxUsed) {
-        this.maxUsed = maxUsed;
-    }
-    
-    public double getCapacity() {
-        return capacity;
-    }
-    
-    public void setCapacity(double capacity) {
-        this.capacity = capacity;
-    }
-    
-    public String getName() {
-        return name;
-    }
-    
-    public void setName(String name) {
-        this.name = name;
-    }
-    
-    public String getTooltip() {
-        return tooltip;
-    }
-    
-    public void setTooltip(String tooltip) {
-        this.tooltip = tooltip;
-    }
-    
-    @Override
-    protected Payload clone() {
-        
-        Payload copy = new Payload();
-        
-        copy.used = used;
-        copy.capacity = capacity;
-        copy.capacityUnit = capacityUnit;
-        copy.maxCapacity = maxCapacity;
-        copy.maxUsed = maxUsed;
-        copy.model = model.clone();
-        copy.name = name;
-        copy.tooltip = tooltip;
-        copy.usedUnit = usedUnit;
-        
-        return copy;
-    }
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/RangeModel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +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.stats.memory;
-
-public class RangeModel {
-
-    private int minNormalized;
-    private double min;
-    
-    private int maxNormalized;
-    private double max;
- 
-    private double value;
- 
-    public double getMinimum() {
-        return min;
-    }
-
-    public void setMinimum(double newMinimum) {
-        this.min = newMinimum;
-    }
-
-    public double getMaximum() {
-        return max;
-    }
-
-    public void setMaximum(double newMaximum) {
-        this.max = newMaximum;
-    }
-
-    public void setMaxNormalized(int maxNormalized) {
-        this.maxNormalized = maxNormalized;
-    }
-    
-    public void setMinNormalized(int minNormalized) {
-        this.minNormalized = minNormalized;
-    }
-    
-    public double getValue() {
-        return value;
-    }
-
-    public void setValue(double newValue) {
-        this.value = newValue;
-    }
-    
-    int getMaxNormalized() {
-        return maxNormalized;
-    }
-    
-    int getMinNormalized() {
-        return minNormalized;
-    }
-    
-    public int getValueNormalized() {
-        double normalized = ((value - min) * (maxNormalized - minNormalized)/(max - min)) + minNormalized;
-        return (int) Math.round(normalized);
-    }
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/StatsModel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,181 +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.stats.memory;
-
-import java.awt.Graphics2D;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
-import java.util.Date;
-
-import javax.swing.plaf.ColorUIResource;
-
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.axis.DateAxis;
-import org.jfree.chart.axis.NumberAxis;
-import org.jfree.chart.plot.XYPlot;
-import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
-import org.jfree.data.time.Millisecond;
-import org.jfree.data.time.TimeSeries;
-import org.jfree.data.time.TimeSeriesCollection;
-import org.jfree.data.xy.XYDataset;
-import org.jfree.ui.RectangleInsets;
-
-public class StatsModel implements Cloneable {
-
-    private static final String lock = new String("MemoryStatsModelLock");
-
-    private String name;
-    
-    private TimeSeries dataSet;
-    
-    public StatsModel() {
-        dataSet = new TimeSeries("");
-    }
-    
-    BufferedImage getChart(int width, int height, ColorUIResource bgColor, ColorUIResource fgColor) {
-        JFreeChart chart = createChart(bgColor, fgColor);
-        
-        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
-        chart.draw((Graphics2D) image.getGraphics(), new Rectangle2D.Double(0, 0, width, height), null);
-        
-        return image;
-    }
-    
-    public String getName() {
-        return name;
-    }
-    
-    public void setName(String name) {
-        dataSet.setDescription(name);
-        this.name = name;
-    }
-    
-    public void setRange(int seconds) {
-        dataSet.setMaximumItemCount(seconds);
-    }
-    
-    public void addData(long timestamp, double value) {
-        Millisecond millisecond = new Millisecond(new Date(timestamp));
-        synchronized (lock) {
-            if (dataSet.getValue(millisecond) == null) {
-                dataSet.add(millisecond, value);
-                dataSet.removeAgedItems(true);
-            }
-        }
-    }
-    
-    @Override
-    protected StatsModel clone() {
-        
-        StatsModel model = new StatsModel();
-        model.setName(name);
-        model.setRange(dataSet.getMaximumItemCount());
-        
-        try {
-            model.dataSet = dataSet.createCopy(0, dataSet.getItemCount() - 1);
-        } catch (CloneNotSupportedException e) {
-            // ah... it's supported here...
-            e.printStackTrace();
-        }
-        
-        return model;
-    }
-    
-    /**
-     * Creates a chart.
-     *
-     * @return a chart.
-     */
-    private JFreeChart createChart(ColorUIResource bgColor, ColorUIResource fgColor) {
-
-        XYDataset priceData = null;
-        synchronized (lock) {            
-            try {
-                priceData = new TimeSeriesCollection(dataSet.createCopy(0,
-                                                     dataSet.getItemCount() - 1));
-            } catch (CloneNotSupportedException e) {
-                e.printStackTrace();
-            }
-        }
-
-        XYPlot plot = new XYPlot();
-        
-        plot.setDomainGridlinesVisible(false);
-        plot.setDomainCrosshairVisible(false);
-        plot.setRangeGridlinesVisible(false);
-        plot.setRangeCrosshairVisible(false);
-                
-        DateAxis dateAxis = new DateAxis();
-        
-        dateAxis.setTickLabelsVisible(false);
-        dateAxis.setTickMarksVisible(false);
-        dateAxis.setAxisLineVisible(false);
-        dateAxis.setNegativeArrowVisible(false);
-        dateAxis.setPositiveArrowVisible(false);
-        dateAxis.setVisible(false);
-        
-        NumberAxis numberAxis = new NumberAxis();
-        numberAxis.setTickLabelsVisible(false);
-        numberAxis.setTickMarksVisible(false);
-        numberAxis.setAxisLineVisible(false);
-        numberAxis.setNegativeArrowVisible(false);
-        numberAxis.setPositiveArrowVisible(false);
-        numberAxis.setVisible(false);
-        numberAxis.setAutoRangeIncludesZero(false);
-        
-        plot.setDomainAxis(dateAxis);
-        plot.setRangeAxis(numberAxis);
-        plot.setDataset(priceData);
-        
-        plot.setInsets(new RectangleInsets(-1, -1, 0, 0));
-        
-        plot.setRenderer(new StandardXYItemRenderer(StandardXYItemRenderer.LINES));
-        plot.setBackgroundPaint(bgColor);
-        
-        JFreeChart chart = new JFreeChart(null, JFreeChart.DEFAULT_TITLE_FONT, plot, false);
-        
-        plot.getRenderer().setSeriesPaint(0, fgColor);
-        chart.setAntiAlias(true);
-        chart.setBorderVisible(false);
-        
-        return chart;
-    }
-    
-    TimeSeries getDataSet() {
-        return dataSet;
-    }
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/SwingMemoryStatsViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.stats.memory;
-
-public class SwingMemoryStatsViewProvider implements MemoryStatsViewProvider {
-
-    @Override
-    public MemoryStatsView createView() {
-        return new MemoryStatsViewImpl();
-    }
-
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/locale/LocaleResources.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +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.stats.memory.locale;
-
-import com.redhat.thermostat.common.locale.Translate;
-
-public enum LocaleResources {
-
-    VM_INFO_TAB_MEMORY,
-    RESOURCE_MISSING;
-    
-    public static final String RESOURCE_BUNDLE =
-            "com.redhat.thermostat.client.stats.memory.locale.strings";
-    
-    public static Translate<LocaleResources> createLocalizer() {
-        return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class);
-    }
-}
--- a/client/memory-stats-panel/src/main/resources/com/redhat/thermostat/client/stats/memory/locale/strings.properties	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-RESOURCE_MISSING = Missing translation!
-VM_INFO_TAB_MEMORY = Memory
\ No newline at end of file
--- a/client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/MemoryStatsControllerTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,269 +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.stats.memory;
-
-import static org.junit.Assert.assertEquals;
-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.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.List;
-import java.util.Map;
-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.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.Timer;
-import com.redhat.thermostat.common.Timer.SchedulingType;
-import com.redhat.thermostat.common.TimerFactory;
-import com.redhat.thermostat.common.appctx.ApplicationContext;
-import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
-import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.model.VmMemoryStat;
-import com.redhat.thermostat.common.model.VmMemoryStat.Generation;
-import com.redhat.thermostat.common.model.VmMemoryStat.Space;
-
-public class MemoryStatsControllerTest {
-
-    private Generation[] generations = new Generation[2];
-    
-    private VmMemoryStatDAO memoryStatDao;
-    private MemoryStatsView view;
-    private Timer timer;
-    
-    private ActionListener<MemoryStatsView.Action> viewListener;
-    
-    private MemoryStatsController controller;
-    
-    private Space canary;
-
-    
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Before
-    public void setUp() {
-        timer = mock(Timer.class);
-        ArgumentCaptor<Runnable> actionCaptor = ArgumentCaptor.forClass(Runnable.class);
-        doNothing().when(timer).setAction(actionCaptor.capture());
-        
-        TimerFactory timerFactory = mock(TimerFactory.class);
-        when(timerFactory.createTimer()).thenReturn(timer);
-        ApplicationContext.getInstance().setTimerFactory(timerFactory);
-        
-        List<VmMemoryStat> vmInfo = new ArrayList<>();
-        
-        for (int i = 0; i < 2; i++) {
-            Generation generation = new Generation();
-            generation.setName("fluff" + i);
-            VmMemoryStat.Space[] spaces = new VmMemoryStat.Space[2 + (1 - i)]; 
-            for (int j = 0; j < 2; j++) {
-                Space space = new Space();
-                space.setName("fluffer" + i + j);
-                space.setUsed(100);
-                space.setCapacity(1000);
-                space.setMaxCapacity(10000);
-                spaces[j] = space;
-            }
-            if (i == 0) {
-                // special payload because the others have all the same values
-                canary = new Space();
-                canary.setName("canary");
-                canary.setUsed(1);
-                canary.setCapacity(2);
-                canary.setMaxCapacity(3);
-                spaces[2] = canary;
-            }
-            generation.setSpaces(spaces);
-            generations[i] = generation;
-        }
-        
-        long timestamp = 1;
-        int vmID = 1;
-        for (int i = 0; i < 5; i++) {
-            VmMemoryStat vmMemory = new VmMemoryStat(timestamp++, vmID, generations);
-            vmInfo.add(vmMemory);
-        }
-        
-        memoryStatDao = mock(VmMemoryStatDAO.class);
-        when(memoryStatDao.getLatestVmMemoryStats(any(VmRef.class), anyLong())).thenReturn(vmInfo);
-        
-        view = mock(MemoryStatsView.class);
-        MemoryStatsViewProvider viewProvider = mock(MemoryStatsViewProvider.class);
-        when(viewProvider.createView()).thenReturn(view);
-        
-        ArgumentCaptor<ActionListener> viewArgumentCaptor =
-                ArgumentCaptor.forClass(ActionListener.class);
-        doNothing().when(view).addActionListener(viewArgumentCaptor.capture());
-
-        VmRef ref = mock(VmRef.class);
-        
-        controller = new MemoryStatsController(memoryStatDao, ref, viewProvider);
-        
-        viewListener = viewArgumentCaptor.getValue();
-    }
-    
-    @Test
-    public void testStartStopTimer() {
-        viewListener.actionPerformed(new ActionEvent<>(view, MemoryStatsView.Action.VISIBLE));
-
-        verify(timer).start();
-        verify(timer).setSchedulingType(SchedulingType.FIXED_RATE);
-
-        viewListener.actionPerformed(new ActionEvent<>(view, MemoryStatsView.Action.HIDDEN));
-
-        verify(timer).stop();
-    }
-
-    @Test
-    public void testPayloadContainSpaces() {
-        MemoryStatsController.VMCollector collettor = controller.getCollector();
-        collettor.run();
-        
-        Map<String, Payload> regions = controller.getRegions();
-        assertEquals(5, regions.size());
-        
-        assertTrue(regions.containsKey("fluffer00"));
-        assertTrue(regions.containsKey("fluffer01"));
-        assertTrue(regions.containsKey("fluffer10"));
-        assertTrue(regions.containsKey("fluffer11"));
-        
-        assertTrue(regions.containsKey("canary"));
-    }
-    
-    @Test
-    public void testValues() {
-        MemoryStatsController.VMCollector collettor = controller.getCollector();
-        collettor.run();
-        
-        Map<String, Payload> regions = controller.getRegions();
-
-        Payload payload = regions.get("fluffer00");
-        assertEquals("fluffer00", payload.getName());
-        assertEquals(10000, payload.getMaxCapacity(), 0);
-        assertEquals(1000, payload.getCapacity(), 0);
-        assertEquals(100, payload.getUsed(), 0);
-        
-        payload = regions.get("canary");
-        assertEquals("canary", payload.getName());
-        assertEquals(3, payload.getMaxCapacity(), 0);
-        assertEquals(2, payload.getCapacity(), 0);
-        assertEquals(1, payload.getUsed(), 0);
-        
-        // the value above all ensure the same scale is used
-        String tooltip = payload.getName() + ": used: " + payload.getUsed() + " " +
-                         payload.getUsedUnit() + ", capacity: " +
-                         payload.getCapacity() + " " + payload.getUsedUnit() +
-                         ", max capacity: " + payload.getMaxCapacity() + " " +
-                         payload.getUsedUnit();
-        
-        assertEquals(tooltip, payload.getTooltip());
-    }
-    
-
-    @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(memoryStatDao.getLatestVmMemoryStats(isA(VmRef.class), anyLong())).thenReturn(Arrays.asList(stat));
-
-        Runnable timerAction = controller.getCollector();
-
-        timerAction.run();
-        timerAction.run();
-
-        verify(memoryStatDao, 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);
-
-        Runnable timerAction = controller.getCollector();
-
-        timerAction.run();
-        timerAction.run();
-
-        verify(memoryStatDao, 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);
-    }
-
-    @After
-    public void tearDown() {
-        ApplicationContextUtil.resetApplicationContext();
-    }
-}
--- a/client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/MemoryStatsPanelActivatorTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +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.stats.memory;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.test.StubBundleContext;
-
-public class MemoryStatsPanelActivatorTest {
-
-    @Test
-    public void verifyStartRegistersViewProvider() throws Exception {
-        StubBundleContext ctx = new StubBundleContext();
-        MemoryStatsPanelActivator activator = new MemoryStatsPanelActivator();
-        activator.start(ctx);
-        assertTrue(ctx.isServiceRegistered(MemoryStatsViewProvider.class.getName(), SwingMemoryStatsViewProvider.class));
-        assertEquals(1, ctx.getAllServices().size());
-    }
-}
--- a/client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/PayloadTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +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.stats.memory;
-
-import static org.junit.Assert.*;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
-
-public class PayloadTest {
-
-    @Test
-    public void testClone() {
-        
-        StatsModel model = new StatsModel();
-        model.setName("fluffModel");
-        model.setRange(100);
-        model.addData(500, 2.0);
-        model.addData(501, 2.1);
-        
-        Payload source = new Payload();
-        source.setCapacity(10.0);
-        source.setName("fluff");
-        source.setCapacityUnit(Scale.GiB);
-        source.setMaxCapacity(100.0);
-        source.setMaxUsed(5.0);
-        source.setUsed(3.0);
-        source.setUsedUnit(Scale.MiB);
-        source.setModel(model);
-        source.setTooltip("fluffTooltip");
-        
-        Payload cloned = source.clone();
-        assertNotSame(cloned, source);
-        
-        assertEquals(source.getName(), cloned.getName());
-        assertEquals(source.getCapacity(), cloned.getCapacity(), 0);
-        assertEquals(source.getCapacityUnit(), cloned.getCapacityUnit());
-        assertEquals(source.getMaxCapacity(), cloned.getMaxCapacity(), 0);
-        assertEquals(source.getMaxUsed(), cloned.getMaxUsed(), 0);
-        assertEquals(source.getTooltip(), cloned.getTooltip());
-        assertEquals(source.getUsed(), cloned.getUsed(), 0);
-        assertEquals(source.getUsedUnit(), cloned.getUsedUnit());
-        assertNotSame(source.getModel(), cloned.getModel());
-
-        assertEquals(source.getModel().getName(), cloned.getModel().getName());
-    }
-}
--- a/client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/RangeModelTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +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.stats.memory;
-
-import static org.junit.Assert.*;
-import junit.framework.Assert;
-
-import org.junit.Test;
-
-public class RangeModelTest {
-
-    @Test
-    public void testSameRange() {
-        RangeModel model = new RangeModel();
-        
-        model.setMaximum(10);
-        model.setMinimum(0);
-        model.setValue(5);
-        
-        model.setMaxNormalized(10);
-        model.setMinNormalized(0);
-        
-        
-        Assert.assertEquals((int) model.getValue(), model.getValueNormalized());
-    }
-
-    @Test
-    public void testDoubleRange() {
-        RangeModel model = new RangeModel();
-        
-        model.setMaximum(10);
-        model.setMinimum(0);
-        model.setValue(5);
-        
-        model.setMaxNormalized(20);
-        model.setMinNormalized(0);
-        
-        
-        Assert.assertEquals(10, model.getValueNormalized());
-    }
-    
-    @Test
-    public void testRanges() {
-        RangeModel model = new RangeModel();
-        
-        model.setMaximum(10);
-        model.setMinimum(0);
-        model.setValue(5);
-        
-        model.setMaxNormalized(40);
-        model.setMinNormalized(0);
-                
-        Assert.assertEquals(20, model.getValueNormalized());
-        
-        model.setMaxNormalized(60);
-        model.setMinNormalized(0);
-                
-        Assert.assertEquals(30, model.getValueNormalized());
-                
-        model.setMaxNormalized(200);
-        model.setMinNormalized(100);
-                
-        Assert.assertEquals(150, model.getValueNormalized());
-        
-        model.setMaximum(100);
-        model.setMinimum(0);
-        model.setValue(50);
-        
-        model.setMaxNormalized(1);
-        model.setMinNormalized(0);
-                
-        Assert.assertEquals(1, model.getValueNormalized());
-        
-        model.setValue(49);
-        Assert.assertEquals(0, model.getValueNormalized());
-        
-        model.setMaximum(1.0);
-        model.setMinimum(0.0);
-        model.setValue(0.5);
-        
-        model.setMaxNormalized(100);
-        model.setMinNormalized(0);
-        
-        Assert.assertEquals(50, model.getValueNormalized());
-        
-        model.setValue(0.72);
-        Assert.assertEquals(72, model.getValueNormalized());
-    }
-}
--- a/client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/StatsModelTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-import static org.junit.Assert.*;
-
-import org.jfree.data.time.TimeSeries;
-import org.junit.Test;
-
-public class StatsModelTest {
-
-    @Test
-    public void testClone() {
-        
-        StatsModel source = new StatsModel();
-        source.setName("fluffModel");
-        source.setRange(100);
-        source.addData(500, 2.0);
-        source.addData(501, 2.1);
-        
-        StatsModel cloned = source.clone();
-        
-        assertNotSame(cloned, source);
-        
-        assertEquals(source.getName(), cloned.getName());
-     
-        assertNotSame(cloned.getDataSet(), source.getDataSet());
-        
-        for (Object series : cloned.getDataSet().getItems()) {
-            assertTrue(source.getDataSet().getItems().contains(series));
-        }
-        
-        assertEquals(cloned.getDataSet().getItemCount(),
-                     source.getDataSet().getItemCount());
-    }
-
-}
--- a/client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/locale/TranslateTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +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.stats.memory.locale;
-
-import java.io.IOException;
-import java.util.Locale;
-import java.util.Properties;
-
-import junit.framework.Assert;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.common.locale.Translate;
-
-public class TranslateTest {
-
-    private Locale lang;
-
-    @Before
-    public void setUp() {
-        this.lang = Locale.getDefault();
-        Locale.setDefault(Locale.US);
-    }
-
-    @After
-    public void tearDown() {
-        Locale.setDefault(lang);
-    }
-
-    @Test
-    public void verifyTranslationsAreThere() 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());
-        Translate<LocaleResources> t = LocaleResources.createLocalizer();
-        Assert.assertEquals("Missing translation!", t.localize(LocaleResources.RESOURCE_MISSING));
-        Assert.assertEquals("Memory", t.localize(LocaleResources.VM_INFO_TAB_MEMORY));
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/swing/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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-osgi-memory-stats-panel</artifactId>
+    <groupId>com.redhat.thermostat</groupId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>thermostat-osgi-memory-stats-panel-swing</artifactId>
+  <packaging>bundle</packaging>
+  <name>Thermostat Client VM Memory Monitor Swing plugin</name>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Private-Package>
+                com.redhat.thermostat.client.stats.memory.swing
+            </Private-Package>
+            <Bundle-Activator>com.redhat.thermostat.client.stats.memory.swing.MemoryStatsPanelActivator</Bundle-Activator>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-SymbolicName>com.redhat.thermostat.client.stats.memory.swing</Bundle-SymbolicName>
+            <!-- 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>org.jfree</groupId>
+      <artifactId>jfreechart</artifactId>
+    </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-osgi-memory-stats-panel-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-client-swing</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/swing/src/main/java/com/redhat/thermostat/client/stats/memory/swing/MemoryGraphPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.stats.memory.swing;
+
+import java.awt.Dimension;
+import java.beans.Transient;
+
+import javax.swing.BoxLayout;
+import javax.swing.JPanel;
+
+import com.redhat.thermostat.client.stats.memory.core.MemoryMeter;
+import com.redhat.thermostat.client.stats.memory.core.Payload;
+
+@SuppressWarnings("serial")
+class MemoryGraphPanel extends JPanel {
+
+    private MemoryMeter meter;
+    
+    /**
+     * Create the panel.
+     */
+    public MemoryGraphPanel() {
+        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
+        meter = new MemoryMeter();
+        add(meter);
+    }
+    
+    public void setMemoryGraphProperties(Payload region) {
+
+        meter.getPrimaryModel().setMinimum(0);
+        meter.getPrimaryModel().setMaximum(region.getMaxUsed());
+        meter.getPrimaryModel().setValue(region.getUsed());
+        
+        meter.getSecondaryModel().setMinimum(0);
+        meter.getSecondaryModel().setMaximum(region.getMaxCapacity());
+        meter.getSecondaryModel().setValue(region.getCapacity());
+        
+        meter.setToolTipText(region.getTooltip());
+        
+        meter.setPrimaryScaleUnit(region.getUsedUnit().toString());
+        meter.setSecondayScaleUnit(region.getCapacityUnit().toString());
+        
+        meter.setStats(region.getModel());
+    }
+    
+    @Override
+    @Transient
+    public Dimension getPreferredSize() {
+        return meter.getPreferredSize();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/swing/src/main/java/com/redhat/thermostat/client/stats/memory/swing/MemoryStatsPanelActivator.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,91 @@
+/*
+ * 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.stats.memory.swing;
+
+import java.util.Map;
+
+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.osgi.service.ApplicationService;
+import com.redhat.thermostat.client.stats.memory.core.MemoryStatsService;
+import com.redhat.thermostat.client.stats.memory.core.MemoryStatsViewProvider;
+import com.redhat.thermostat.common.MultipleServiceTracker;
+import com.redhat.thermostat.common.MultipleServiceTracker.Action;
+import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
+
+public class MemoryStatsPanelActivator implements BundleActivator {
+
+    private MultipleServiceTracker tracker;
+    private ServiceRegistration memoryStatRegistration;
+
+    @Override
+    public void start(final BundleContext context) throws Exception {
+        MemoryStatsViewProvider provider = new SwingMemoryStatsViewProvider();
+        context.registerService(MemoryStatsViewProvider.class.getName(), provider, null);
+        
+        Class<?>[] deps = new Class<?>[] {
+            ApplicationService.class,
+            VmMemoryStatDAO.class,
+        };
+
+        tracker = new MultipleServiceTracker(context, deps, new Action() {
+            
+            @Override
+            public void dependenciesUnavailable() {
+                memoryStatRegistration.unregister();
+                memoryStatRegistration = null;
+            }
+
+            @Override
+            public void dependenciesAvailable(Map<String, Object> services) {
+                VmMemoryStatDAO memoryStatDao = (VmMemoryStatDAO) services.get(VmMemoryStatDAO.class.getName());
+                MemoryStatsService impl = new MemoryStatsService(memoryStatDao);
+                memoryStatRegistration = context.registerService(VmInformationService.class.getName(), impl , null);
+            }
+        });
+        tracker.open();
+
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        tracker.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/swing/src/main/java/com/redhat/thermostat/client/stats/memory/swing/MemoryStatsViewImpl.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.stats.memory.swing;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.beans.Transient;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.stats.memory.core.MemoryStatsView;
+import com.redhat.thermostat.client.stats.memory.core.Payload;
+import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.client.swing.components.HeaderPanel;
+import com.redhat.thermostat.client.ui.ComponentVisibleListener;
+
+public class MemoryStatsViewImpl extends MemoryStatsView implements SwingComponent {
+
+    private static final long REPAINT_DELAY = 500;
+    private long lastRepaint;
+    
+    private HeaderPanel visiblePanel;
+    private JPanel realPanel;
+    
+    private final Map<String, MemoryGraphPanel> regions;
+    
+    private Dimension preferredSize;
+    
+    public MemoryStatsViewImpl() {
+        super();
+        visiblePanel = new HeaderPanel();
+        regions = new HashMap<>();
+ 
+        preferredSize = new Dimension(0, 0);
+        
+        visiblePanel.setHeader("Memory Regions");
+
+        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+
+            @Override
+            public void componentHidden(Component component) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
+
+        realPanel = new JPanel();
+        realPanel.setLayout(new BoxLayout(realPanel, BoxLayout.Y_AXIS));
+        visiblePanel.setContent(realPanel);
+    }
+    
+    @Transient
+    public Dimension getPreferredSize() {
+        return new Dimension(preferredSize);
+    }
+    
+    @Override
+    public void updateRegion(final Payload region) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                MemoryGraphPanel memoryGraphPanel = regions.get(region.getName());
+                memoryGraphPanel.setMemoryGraphProperties(region);
+            }
+        });
+    }
+    
+    @Override
+    public void addRegion(final Payload region) {
+
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                MemoryGraphPanel memoryGraphPanel = new MemoryGraphPanel();
+                
+                realPanel.add(memoryGraphPanel);
+                realPanel.add(Box.createRigidArea(new Dimension(5,5)));
+                regions.put(region.getName(), memoryGraphPanel);
+                
+                // components are stacked up vertically in this panel
+                Dimension memoryGraphPanelMinSize = memoryGraphPanel.getMinimumSize();
+                preferredSize.height += memoryGraphPanelMinSize.height + 5;
+                if (preferredSize.width < (memoryGraphPanelMinSize.width + 5)) {
+                    preferredSize.width = memoryGraphPanelMinSize.width + 5;
+                }
+
+                updateRegion(region);
+                realPanel.revalidate();
+            }
+        });
+    }
+
+    @Override
+    public Component getUiComponent() {
+        return visiblePanel;
+    }
+
+    @Override
+    public void requestRepaint() {
+        // really only repaint every REPAINT_DELAY milliseconds
+        long now = System.currentTimeMillis();
+        if (now - lastRepaint > REPAINT_DELAY) {
+            visiblePanel.repaint();
+            lastRepaint = System.currentTimeMillis();
+        }
+    }
+    
+    public BasicView getView() {
+        return this;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/swing/src/main/java/com/redhat/thermostat/client/stats/memory/swing/SwingMemoryStatsViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.stats.memory.swing;
+
+import com.redhat.thermostat.client.stats.memory.core.MemoryStatsView;
+import com.redhat.thermostat.client.stats.memory.core.MemoryStatsViewProvider;
+
+public class SwingMemoryStatsViewProvider implements MemoryStatsViewProvider {
+
+    @Override
+    public MemoryStatsView createView() {
+        return new MemoryStatsViewImpl();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/swing/src/main/resources/com/redhat/thermostat/client/stats/memory/locale/strings.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,2 @@
+RESOURCE_MISSING = Missing translation!
+VM_INFO_TAB_MEMORY = Memory
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/swing/src/test/java/com/redhat/thermostat/client/stats/memory/swing/MemoryStatsPanelActivatorTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,57 @@
+/*
+ * 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.stats.memory.swing;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.client.stats.memory.core.MemoryStatsViewProvider;
+import com.redhat.thermostat.test.StubBundleContext;
+
+public class MemoryStatsPanelActivatorTest {
+
+    @Test
+    public void verifyStartRegistersViewProvider() throws Exception {
+        StubBundleContext ctx = new StubBundleContext();
+        MemoryStatsPanelActivator activator = new MemoryStatsPanelActivator();
+        activator.start(ctx);
+        assertTrue(ctx.isServiceRegistered(MemoryStatsViewProvider.class.getName(), SwingMemoryStatsViewProvider.class));
+        assertEquals(1, ctx.getAllServices().size());
+    }
+}
--- a/client/pom.xml	Fri Oct 26 13:13:42 2012 +0200
+++ b/client/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -65,7 +65,7 @@
     <module>memory-stats-panel</module>
     <module>living-vm-filter</module>
     <module>command</module>
-    <module>swing-components</module>
+    <module>swing</module>
   </modules>
 
 </project>
--- a/client/swing-components/pom.xml	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-<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</artifactId>
-    <groupId>com.redhat.thermostat</groupId>
-    <version>0.5.0-SNAPSHOT</version>
-  </parent>
-  
-  <artifactId>thermostat-swing-components</artifactId>
-  <packaging>bundle</packaging>
-  <name>Swing Components and Utilities</name>
-  
-  <properties>
-    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-  </properties>
-  
-  <dependencies>
-
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-common-core</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <scope>test</scope>
-    </dependency>
-    
-    <dependency>
-      <groupId>org.jfree</groupId>
-      <artifactId>jfreechart</artifactId>
-    </dependency>
-    
-    <dependency>
-      <groupId>net.java.openjdk.cacio</groupId>
-      <artifactId>cacio-tta</artifactId>
-      <scope>test</scope>
-    </dependency>
-    
-  </dependencies>
-      
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <configuration>
-          <instructions>
-            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
-            <Bundle-SymbolicName>com.redhat.thermostat.client.swing.components</Bundle-SymbolicName>
-            <Export-Package>
-              com.redhat.thermostat.swing,
-              com.redhat.thermostat.models,
-              com.redhat.thermostat.swing.models,
-              com.redhat.thermostat.charts
-            </Export-Package>
-            <!-- Do not autogenerate uses clauses in Manifests -->
-            <_nouses>true</_nouses>
-          </instructions>
-        </configuration>
-      </plugin>
-    </plugins>
-
-  </build>
-  
-</project>
--- a/client/swing-components/src/main/java/com/redhat/thermostat/charts/BytesTickUnit.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.charts;
-
-import org.jfree.chart.axis.NumberTickUnit;
-
-import com.redhat.thermostat.common.utils.DisplayableValues;
-
-@SuppressWarnings("serial")
-public class BytesTickUnit extends NumberTickUnit {
-
-    public BytesTickUnit(double size) {
-        super(size);
-    }
-
-    @Override
-    public String valueToString(double value) {
-        String[] displayable = DisplayableValues.bytes((long) value);
-        return displayable[0] + " " + displayable[1];
-    }
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/ActionButton.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.swing;
-
-import javax.swing.AbstractButton;
-import javax.swing.Icon;
-import javax.swing.JButton;
-
-@SuppressWarnings("serial")
-public class ActionButton extends JButton implements ToolbarButton {
-
-    private AbstractButton realButton;
-    
-    public ActionButton(final Icon icon) {
-        super(icon);
-        
-        realButton = new JButton() {
-            @Override
-            public int getWidth() {
-                return icon.getIconWidth() + 5;
-            }
-            
-            @Override
-            public int getHeight() {
-                return icon.getIconHeight() + 4;
-            }
-        };
-        setUI(new ActionButtonUI(realButton));
-        
-        setSize(realButton.getWidth(), realButton.getHeight());
-        setContentAreaFilled(false);
-        
-        setPreferredSize(getSize());
-        setMinimumSize(getSize());
-        setMaximumSize(getSize());
-        
-        realButton.setModel(getModel());
-
-        setBorderPainted(false);
-    }
-    
-    @Override
-    public AbstractButton getToolbarButton() {
-        return this;
-    }
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/ActionButtonUI.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.swing;
-
-import java.awt.Graphics;
-import java.awt.image.BufferedImage;
-import java.awt.image.BufferedImageOp;
-import java.awt.image.ConvolveOp;
-import java.awt.image.Kernel;
-
-import javax.swing.AbstractButton;
-import javax.swing.ButtonModel;
-import javax.swing.Icon;
-import javax.swing.JComponent;
-import javax.swing.border.Border;
-import javax.swing.plaf.metal.MetalButtonUI;
-
-class ActionButtonUI extends MetalButtonUI {
-
-    private BufferedImage sourceIcon;
-    private BufferedImage rollOverIcon;
-    private AbstractButton realButton;
-    
-    ActionButtonUI(AbstractButton button) {
-        this.realButton = button;
-    }
-    
-    private BufferedImage getBrighterImage(BufferedImage source) {
-        float[] kernel = new float[] { 0, 0, 0, 0, 1.2f, 0, 0, 0, 0 };
-
-        BufferedImageOp brighterOp = new ConvolveOp(new Kernel(3, 3, kernel),
-                ConvolveOp.EDGE_NO_OP, null);
-        return brighterOp.filter(source, new BufferedImage(source.getWidth(),
-                source.getHeight(), source.getType()));
-    }
-
-    @Override
-    public void paint(Graphics g, JComponent c) {
-
-        AbstractButton button = (AbstractButton) c;
-        ButtonModel model = button.getModel();
-        if (model.isPressed() || model.isArmed() || model.isSelected()) {
-            realButton.paint(g);
-        } else if (model.isRollover()) {
-            Border border = realButton.getBorder();
-            border.paintBorder(realButton, g, 0, 0, realButton.getWidth(),
-                    realButton.getHeight());
-        }
-        // paint the icon, always to the center
-        Icon icon = button.getIcon();
-        int w = icon.getIconWidth();
-        int h = icon.getIconHeight();
-
-        if (sourceIcon == null) {
-            sourceIcon = new BufferedImage(w + 1, h + 1,
-                    BufferedImage.TYPE_INT_ARGB);
-            Graphics imageGraphics = sourceIcon.getGraphics();
-            icon.paintIcon(null, imageGraphics, 0, 0);
-        }
-
-        if (rollOverIcon == null) {
-            rollOverIcon = getBrighterImage(sourceIcon);
-        }
-
-        int x = realButton.getWidth() / 2 - w / 2;
-        int y = realButton.getHeight() / 2 - h / 2;
-
-        if (model.isRollover()) {
-            g.drawImage(rollOverIcon, x, y, null);
-        } else {
-            g.drawImage(sourceIcon, x, y, null);
-        }
-    }
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/ActionToggleButton.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +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.swing;
-
-import javax.swing.AbstractButton;
-import javax.swing.Icon;
-import javax.swing.JToggleButton;
-
-@SuppressWarnings("serial")
-public class ActionToggleButton extends JToggleButton implements ToolbarButton {
-    private AbstractButton realButton;
-    
-    public ActionToggleButton(final Icon icon) {
-        super(icon);
-        
-        realButton = new JToggleButton() {
-            @Override
-            public int getWidth() {
-                return icon.getIconWidth() + 4;
-            }
-            
-            @Override
-            public int getHeight() {
-                return icon.getIconHeight() + 4;
-            }
-        };
-        setUI(new ActionButtonUI(realButton));
-        
-        setSize(realButton.getWidth(), realButton.getHeight());
-        setContentAreaFilled(false);
-        
-        setPreferredSize(getSize());
-        setMinimumSize(getSize());
-        setMaximumSize(getSize());
-        
-        realButton.setModel(getModel());
-
-        setBorderPainted(false);
-    }
-    
-    @Override
-    public AbstractButton getToolbarButton() {
-        return this;
-    }    
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/ChartPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.swing;
-
-import java.awt.Graphics;
-import java.awt.image.BufferedImage;
-
-import javax.swing.JPanel;
-
-import org.jfree.chart.ChartRenderingInfo;
-import org.jfree.chart.JFreeChart;
-
-@SuppressWarnings("serial")
-public class ChartPanel extends JPanel {
-
-    private JFreeChart chart;
-    private ChartRenderingInfo info;
-    
-    public ChartPanel(JFreeChart chart) {
-        this(chart, new ChartRenderingInfo());
-    }
-    
-    public ChartPanel(JFreeChart chart, ChartRenderingInfo info) {
-        this.chart = chart;
-        this.info = info;
-    }
-    
-    @Override
-    protected void paintComponent(Graphics g) {
-        BufferedImage image = chart.createBufferedImage(getWidth(), getHeight(), info);
-        g.drawImage(image, 0, 0, null);
-    }
-    
-    public ChartRenderingInfo getChartRenderingInfo() {
-        return info;
-    }
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/DebugBorder.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +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.swing;
-
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Insets;
-import java.awt.Shape;
-import java.awt.geom.RoundRectangle2D;
-import java.io.Serializable;
-
-import javax.swing.border.AbstractBorder;
-import javax.swing.plaf.UIResource;
-
-@SuppressWarnings("serial")
-public class DebugBorder extends AbstractBorder implements UIResource, Serializable {
-
-    @Override
-    public void paintBorder(Component c, Graphics g, int x, int y, int width,
-                            int height)
-    {
-        Graphics2D graphics = (Graphics2D) g.create();
-
-        graphics.translate(x, y);
-        
-        graphics.setPaint(Color.RED);
-        
-        float dash[] = { 10.0f };
-        graphics.setStroke(new BasicStroke(3.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f));
-        
-        Shape shape = new RoundRectangle2D.Float(0, 0, width - 1,
-                                                 height - 1, 4, 4);
-        graphics.draw(shape);
-        graphics.dispose();
-    }
-    
-    @Override
-    public Insets getBorderInsets(Component c) {
-        return getBorderInsets(c, new Insets(0, 0, 0, 0));
-    }
-
-    @Override
-    public Insets getBorderInsets(Component c, Insets insets) {
-        
-        insets.top = 4;
-        insets.left = 4;
-        insets.right = 4;
-        insets.bottom = 4;
-        
-        return insets;
-    }
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/EdtHelper.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +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.swing;
-
-import java.awt.EventQueue;
-import java.lang.reflect.InvocationTargetException;
-import java.util.concurrent.Callable;
-
-public class EdtHelper {
-
-    @SuppressWarnings("serial")
-    private static class CallableException extends RuntimeException {
-
-        private CallableException(Exception ex) {
-            super(ex);
-        }
-        
-    }
-
-    private static class CallableWrapper<T> implements Runnable {
-
-        private Callable<T> callable;
-        private T result;
-
-        private CallableWrapper(Callable<T> c) {
-            callable = c;
-        }
-
-        @Override
-        public void run() {
-            try {
-                result = callable.call();
-            } catch (Exception ex) {
-                throw new CallableException(ex);
-            }
-        }
-
-        private T getResult() {
-            return result;
-        }
-    }
-
-    public void callAndWait(Runnable r) throws InvocationTargetException, InterruptedException {
-        if (EventQueue.isDispatchThread()) {
-            try {
-                r.run();
-            } catch (Exception ex) {
-                throw new InvocationTargetException(ex);
-            }
-        } else {
-            EventQueue.invokeAndWait(r);
-        }
-    }
-
-    public <T> T callAndWait(Callable<T> c) throws InvocationTargetException, InterruptedException {
-        CallableWrapper<T> w = new CallableWrapper<>(c);
-        callAndWait(w);
-        return w.getResult();
-    }
-
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/EmptyIcon.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.swing;
-
-import java.awt.Component;
-import java.awt.Graphics;
-
-import javax.swing.ImageIcon;
-
-@SuppressWarnings("serial")
-public class EmptyIcon extends ImageIcon  {
-
-    private int width;
-    private int height;
-    
-    public EmptyIcon() {
-        this(16, 16);
-    }
-    
-    public EmptyIcon(int width, int height) {
-        this.width = width;
-        this.height = height;
-    }
-    
-    @Override
-    public int getIconHeight() {
-        return height;
-    }
-    
-    @Override
-    public int getIconWidth() {
-        return width;
-    }
-    
-    @Override
-    public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
-        // no-op
-    }
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/GradientPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +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.swing;
-
-import java.awt.Color;
-import java.awt.GradientPaint;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Paint;
-
-import javax.swing.JPanel;
-
-
-@SuppressWarnings("serial")
-public class GradientPanel extends JPanel {
-
-    private Color top;
-    private Color bottom;
-    
-    public GradientPanel(Color top, Color bottom) {
-        this.top = top;
-        this.bottom = bottom;
-    }
-    
-    @Override
-    protected void paintComponent(Graphics g) {
-        
-        Graphics2D graphics = GraphicsUtils.getInstance().createAAGraphics(g);
-        
-        Paint gradient = new GradientPaint(0, 0, top, 0, getHeight(), bottom);
-        graphics.setPaint(gradient);
-        graphics.fillRect(0, 0, getWidth(), getHeight());
-        graphics.dispose();
-    }
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/GradientRoundBorder.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +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.swing;
-
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.GradientPaint;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Paint;
-import java.awt.Shape;
-import java.io.Serializable;
-
-import javax.swing.UIManager;
-import javax.swing.border.AbstractBorder;
-import javax.swing.plaf.UIResource;
-
-@SuppressWarnings("serial")
-public class GradientRoundBorder extends AbstractBorder implements UIResource, Serializable {
-
-    @Override
-    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
-        GraphicsUtils utils = GraphicsUtils.getInstance();
-        Graphics2D graphics = utils.createAAGraphics(g);
-        
-        Color highlight = UIManager.getColor("textHighlight");
-        if (highlight == null) {
-            highlight = Palette.EGYPTIAN_BLUE.getColor();
-        }
-        Paint paint = new GradientPaint(x, y, highlight, 0, height, c.getBackground());
-        graphics.setPaint(paint);
-        
-        graphics.translate(x, y);
-        
-        Shape shape = utils.getRoundShape(width, height);
-        graphics.draw(shape);
-        
-        graphics.dispose();
-    }
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/GraphicsUtils.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +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.swing;
-
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.FontMetrics;
-import java.awt.GradientPaint;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Paint;
-import java.awt.RenderingHints;
-import java.awt.Shape;
-import java.awt.geom.RoundRectangle2D;
-
-import javax.swing.JComponent;
-
-import sun.swing.SwingUtilities2;
-
-@SuppressWarnings("restriction")
-public class GraphicsUtils {
-
-    private static GraphicsUtils instance = new GraphicsUtils();
-    public static GraphicsUtils getInstance() {
-        return instance;
-    }
-    
-    public Graphics2D createAAGraphics(Graphics g) {
-        Graphics2D graphics = (Graphics2D) g.create();
-        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-        return graphics;
-    }
-    
-    public void drawStringWithShadow(JComponent component, Graphics2D graphics, String string, Color foreground, int x, int y) {
-        // paint it twice to give a subtle drop shadow effect
-        
-        graphics.setColor(new Color(0f, 0f, 0f, 0.1f));
-        SwingUtilities2.drawString(component, graphics, string, x, y + 1);
-        
-        graphics.setColor(foreground);
-        SwingUtilities2.drawString(component, graphics, string, x, y);
-    }
-    
-    public void drawString(JComponent component, Graphics2D graphics, String string, Color foreground, int x, int y) {
-        graphics.setColor(foreground);
-        SwingUtilities2.drawString(component, graphics, string, x, y);
-    }
-    
-    public FontMetrics getFontMetrics(JComponent component, Font font) {
-        return SwingUtilities2.getFontMetrics(component, font);
-    }
-    
-    public Shape getRoundShape(int width, int height) {
-        return new RoundRectangle2D.Double(0, 0, width, height, 4, 4);
-    }
-    
-    public void setGradientPaint(Graphics2D g, int x, int height, Color start, Color stop) {
-        Paint paint = new GradientPaint(x, 0, start, 0, height, stop);
-        g.setPaint(paint);
-    }
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/HeaderPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +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.swing;
-
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.FlowLayout;
-import java.lang.reflect.InvocationTargetException;
-
-import javax.swing.BoxLayout;
-import javax.swing.JComponent;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.SwingUtilities;
-
-/**
- * A component that host a panel with a nicely rendered header.
- */
-@SuppressWarnings("serial")
-public class HeaderPanel extends JPanel {
-    
-    private String header;
-    
-    private JPanel contentPanel;
-    private JLabel headerLabel;
-    private JPanel headerPanel;
-    private JPanel controlPanel;
-    
-    public HeaderPanel() {
-        this("");
-    }
-    
-    public HeaderPanel(String header) {
-        
-        this.header = header;
-        
-        setLayout(new BorderLayout(0, 0));
-
-        headerLabel = new ShadowLabel(header, new EmptyIcon(5, 5));
-        headerPanel = new GradientPanel(Color.WHITE, getBackground());
-        headerPanel.setPreferredSize(new Dimension(HeaderPanel.this.getWidth(), 40));
-        
-        headerPanel.setLayout(new BorderLayout(0, 0));
-        headerPanel.add(headerLabel, BorderLayout.WEST);
-        add(headerPanel, BorderLayout.NORTH);
-        
-        controlPanel = new JPanel();
-        controlPanel.setOpaque(false);
-        controlPanel.setLayout(new FlowLayout(FlowLayout.RIGHT, 2, 10));
-        
-        headerPanel.add(controlPanel, BorderLayout.EAST);
-        
-        contentPanel = new JPanel();
-        contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.X_AXIS));
-        
-        add(contentPanel, BorderLayout.CENTER);
-    }
-   
-    public String getHeader() {
-        return header;
-    }
-    
-    public void setHeader(String header) {
-        this.header = header;
-        headerLabel.setText(header);
-    }
-    
-    public void setContent(JComponent content) {
-        contentPanel.removeAll();
-        contentPanel.add(content);
-        contentPanel.revalidate();
-        repaint();
-    }
-
-    public void addToolBarButton(ToolbarButton button) {
-        controlPanel.add(button.getToolbarButton());
-    }
-    
-    public static void main(String[] args) throws InvocationTargetException, InterruptedException {
-        SwingUtilities.invokeAndWait(new Runnable() {
-            
-            @Override
-            public void run() {
-               JFrame frame = new JFrame();
-               frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-               
-               HeaderPanel header = new HeaderPanel();
-               header.setHeader("Test");
-               frame.getContentPane().add(header);
-               frame.setSize(500, 500);
-               frame.setVisible(true);
-            }
-        });
-    }
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/Palette.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.swing;
-
-import java.awt.Color;
-
-public enum Palette {
-
-    THERMOSTAT_BLU(new Color(74, 93, 117)),
-    THERMOSTAT_RED(new Color(226, 46, 42)),
-    
-    RED(new Color(192, 0, 0)),
-    PALE_RED(new Color(192, 80, 77)),
-    
-    SKY_BLUE(new Color(79, 129, 189)),
-    AZUREUS(new Color(0, 176, 190)),
-    EGYPTIAN_BLUE(new Color(74, 144, 217)),
-    DIRTY_CYAN(new Color(75, 172, 198)),
-    PRUSSIAN_BLUE(new Color(0, 49, 83)),
-    
-    GREEN(new Color(146, 208, 80)),
-    TUNDRA_GREEN(new Color(155, 187, 89)),
-
-    POMP_AND_POWER_VIOLET(new Color(128, 100, 162)),
-    VIOLET(new Color(112, 48, 160)),
-
-    EARL_GRAY(new Color(128, 128, 128)),
-    
-    PALE_GRAY(new Color(235, 235, 235)),
-    LIGHT_GRAY(new Color(242, 242, 242)),
-    GRAY(new Color(216, 216, 216)),
-    DARK_GRAY(new Color(168, 172, 168)),
-
-    GRANITA_ORANGE(new Color(247,150,70)),
-    
-    BLACK(Color.BLACK),
-    WHITE(Color.WHITE),
-
-    /* END */ ;
-    
-    private Color color;
-    Palette(Color color) {
-        this.color = color;
-    }
-    
-    public Color getColor() {
-        return color;
-    }
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/ShadowLabel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +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.swing;
-
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-
-import javax.swing.Icon;
-import javax.swing.JLabel;
-import javax.swing.plaf.metal.MetalLabelUI;
-
-@SuppressWarnings("serial")
-public class ShadowLabel extends JLabel {
-
-    public ShadowLabel(String text, Icon icon) {
-        super(text);
-        this.setIcon(icon);
-        setUI(new ShadowLabelUI());
-    }
-    
-    public ShadowLabel(String text) {
-        this(text, null);
-    }
-
-    private class ShadowLabelUI extends MetalLabelUI {
-        
-        @Override
-        protected void paintEnabledText(JLabel l, Graphics g, String s, int textX, int textY) {
-            GraphicsUtils graphicsUtils = GraphicsUtils.getInstance();
-            Graphics2D graphics = graphicsUtils.createAAGraphics(g);
-            graphicsUtils.drawStringWithShadow(l, graphics, s, getForeground(), textX, textY);
-        }
-    }
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/StatusBar.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.swing;
-
-import java.awt.BorderLayout;
-import java.awt.Dimension;
-import java.beans.Transient;
-
-import javax.swing.ImageIcon;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.SwingUtilities;
-
-@SuppressWarnings("serial")
-public class StatusBar extends JPanel {
-
-    // some of this code is inspired by the book
-    // Swing Hacks: Tips & Tools for Building Killer GUIs
-    // By Joshua Marinacci, Chris Adamson
-    // ISBN: 0-596-00907-0
-    // website: http://www.oreilly.com/catalog/swinghks/
-
-    public static final String PRIMARY_STATUS_PROPERTY = "primaryStatus";
-    
-    private Dimension preferredSize;
-    
-    private String primaryStatus = "";
-    private JLabel primaryStatusLabel;
-    private JLabel iconLabel;
-    
-    public StatusBar() {
-        super();
-        setLayout(new BorderLayout(0, 0));
-        
-        primaryStatusLabel = new JLabel(primaryStatus);
-        primaryStatusLabel.setName("primaryStatusLabel");
-        primaryStatusLabel.setFont(getFont().deriveFont(10.0f));
-        primaryStatusLabel.setHorizontalAlignment(JLabel.LEADING);
-        primaryStatusLabel.setVerticalAlignment(JLabel.CENTER);
-
-        add(primaryStatusLabel, BorderLayout.WEST);
-        
-        iconLabel = new JLabel("");
-        ImageIcon grip = new ImageIcon(getClass().getResource("/icons/resize-grip.png"));
-        iconLabel.setIcon(grip);
-
-        iconLabel.setMinimumSize(new Dimension(grip.getIconWidth() + 1, grip.getIconHeight()));
-        iconLabel.setPreferredSize(new Dimension(grip.getIconWidth() + 1, grip.getIconHeight()));
-        iconLabel.setVerticalAlignment(JLabel.BOTTOM);
-
-        add(iconLabel, BorderLayout.EAST);
-        preferredSize = new Dimension(700, grip.getIconHeight() + 5);
-    }
-    
-    @Override
-    @Transient
-    public Dimension getMinimumSize() {
-        if (isMinimumSizeSet()) {
-            return super.getMinimumSize();
-        }
-        return preferredSize;
-    }
-    
-    @Override
-    @Transient
-    public Dimension getPreferredSize() {
-        if (isPreferredSizeSet()) {
-            return super.getPreferredSize();
-        }
-        return preferredSize;
-    }
-    
-    public void setPrimaryStatus(String primaryStatus) {
-        if (primaryStatus == null) throw new NullPointerException();
-        
-        String oldPrimaryStatus = this.primaryStatus;
-        this.primaryStatus = primaryStatus;
-        primaryStatusLabel.setText(" " + primaryStatus);
-        
-        firePropertyChange(PRIMARY_STATUS_PROPERTY, oldPrimaryStatus, this.primaryStatus);
-        repaint();
-    }
-
-    public String getPrimaryStatus() {
-        return primaryStatus;
-    }
-        
-    public static void main(String[] args) {
-        SwingUtilities.invokeLater(new Runnable() {
-            
-            @Override
-            public void run() {
-                JFrame frame = new JFrame();
-                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-                frame.getContentPane().setLayout(new BorderLayout());
-                
-                StatusBar statusBar = new StatusBar();
-                frame.getContentPane().add(statusBar, BorderLayout.SOUTH);
-                
-                frame.setSize(500, 500);
-                frame.setVisible(true);
-            }
-        });
-    }
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/ThermostatTable.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +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.swing;
-
-import java.awt.Dimension;
-
-import javax.swing.JScrollPane;
-import javax.swing.JTable;
-import javax.swing.table.DefaultTableModel;
-
-@SuppressWarnings("serial")
-public class ThermostatTable extends JTable {
-    
-    private ThermostatTableColumnResizer resizer;
-    
-    public ThermostatTable() {
-        this((DefaultTableModel) null);
-    }
-    
-    public ThermostatTable(int rowHeight) {
-        this((DefaultTableModel) null, rowHeight);
-    }
-    
-    public ThermostatTable(DefaultTableModel model) {
-        this((DefaultTableModel) model, 25);
-    }
-    
-    public ThermostatTable(DefaultTableModel model, int rowHeight) {
-        super(model);
-
-        setRowHeight(rowHeight);
-        
-        setIntercellSpacing(new Dimension(0, 0));
-        
-        setFillsViewportHeight(true);
-        setAutoCreateRowSorter(true);
-        
-        setDefaultRenderer(Object.class, new ThermostatTableRenderer());
-        setDefaultRenderer(Double.class, new ThermostatTableRenderer());
-        setDefaultRenderer(Long.class, new ThermostatTableRenderer());
-        setDefaultRenderer(String.class, new ThermostatTableRenderer());
-        setDefaultRenderer(Integer.class, new ThermostatTableRenderer());
-        
-        this.resizer = new ThermostatTableColumnResizer(this);
-    }
-    
-    public void repackCells() {
-        resizer.resize();
-        revalidate();
-    }
-    
-    public JScrollPane wrap() {        
-        JScrollPane scrollPane = new JScrollPane(this);
-        repackCells();
-        return scrollPane;
-    }
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/ThermostatTableColumnResizer.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.swing;
-
-import java.awt.Component;
-
-import javax.swing.table.TableCellRenderer;
-import javax.swing.table.TableColumn;
-import javax.swing.table.TableColumnModel;
-
-class ThermostatTableColumnResizer {
-    
-    // reference Swing Hacks book:
-    // http://shop.oreilly.com/product/9780596009076.do
-    
-    private ThermostatTable table;
-    
-    public ThermostatTableColumnResizer(ThermostatTable table) {
-        this.table = table;
-    }
-    
-    public void resize() {
-        TableColumnModel model = table.getColumnModel();
-        for (int column = 0; column < table.getColumnCount(); column++ ) {
-            int maxWidth = 0;
-            for (int row = 0; row < table.getRowCount(); row++ ) {
-                TableCellRenderer renderer = table.getCellRenderer(row, column);
-                Object value = table.getValueAt(row, column);
-                Component component = renderer.getTableCellRendererComponent(table, value, false, false, row, column);
-                maxWidth = Math.max(component.getPreferredSize().width, maxWidth);
-            }
-            
-            TableColumn tableColumn = model.getColumn(column);
-            TableCellRenderer headerRenderer = tableColumn.getHeaderRenderer();
-            if (headerRenderer == null) {
-                headerRenderer = table.getTableHeader().getDefaultRenderer(); 
-            }
-            
-            Object headerValue = tableColumn.getHeaderValue();
-            Component headerComponent = headerRenderer.getTableCellRendererComponent(table, headerValue, false, false, 0, column);
-            maxWidth = Math.max(maxWidth, headerComponent.getPreferredSize().width);
-            
-            tableColumn.setPreferredWidth(maxWidth);
-        }
-    }
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/ThermostatTableRenderer.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +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.swing;
-
-import java.awt.Component;
-
-import javax.swing.JTable;
-import javax.swing.table.DefaultTableCellRenderer;
-
-@SuppressWarnings("serial")
-public class ThermostatTableRenderer extends DefaultTableCellRenderer {
-
-    @Override
-    public Component getTableCellRendererComponent(JTable table, Object value,
-            boolean isSelected, boolean hasFocus, int row, int column) {
-
-        Component result = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
-        if (result == null || isSelected) {
-            // do nothing
-        } else if (!isEven(row)) {
-            result.setBackground(Palette.LIGHT_GRAY.getColor());
-        } else {
-            result.setBackground(Palette.WHITE.getColor());
-        }
-        
-        return result;
-    }
-
-    private boolean isEven(int row) {
-        return row % 2 == 0;
-    }
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/ToolbarButton.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +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.swing;
-
-import javax.swing.AbstractButton;
-
-public interface ToolbarButton {
-    AbstractButton getToolbarButton();
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/models/LongRange.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +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.swing.models;
-
-public class LongRange {
-
-    long min;
-    long max;
-    
-    public void setMax(long max) {
-        this.max = max;
-    }
-    
-    public long getMax() {
-        return max;
-    }
-    
-    public void setMin(long min) {
-        this.min = min;
-    }
-    
-    
-    public long getMin() {
-        return min;
-    }
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/models/LongRangeNormalizer.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.swing.models;
-
-public class LongRangeNormalizer {
-
-    private long minNormalized;
-    
-    private long maxNormalized;
- 
-    private long value;
-
-    private LongRange range;
-    
-    public LongRangeNormalizer(LongRange range) {
-        this.range = range;
-    }
-
-    public void setMaxNormalized(long maxNormalized) {
-        this.maxNormalized = maxNormalized;
-    }
-    
-    public void setMinNormalized(long minNormalized) {
-        this.minNormalized = minNormalized;
-    }
-    
-    public long getValue() {
-        return value;
-    }
-
-    public void setValue(long newValue) {
-        this.value = newValue;
-    }
-    
-    public long getMaxNormalized() {
-        return maxNormalized;
-    }
-    
-    public long getMinNormalized() {
-        return minNormalized;
-    }
-    
-    public long getValueNormalized() {
-        double normalized = ((value - range.min) * (double)(maxNormalized - minNormalized)/(range.max - range.min)) + minNormalized;
-        return Math.round(normalized);
-    }
-}
--- a/client/swing-components/src/main/java/com/redhat/thermostat/swing/models/NullSelectionModel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.swing.models;
-
-import javax.swing.ListSelectionModel;
-import javax.swing.event.ListSelectionListener;
-
-public class NullSelectionModel implements ListSelectionModel {
-
-    @Override
-    public void setSelectionInterval(int index0, int index1) {
-    }
-
-    @Override
-    public void addSelectionInterval(int index0, int index1) {
-    }
-
-    @Override
-    public void removeSelectionInterval(int index0, int index1) {        
-    }
-
-    @Override
-    public int getMinSelectionIndex() {
-        return 0;
-    }
-
-    @Override
-    public int getMaxSelectionIndex() {
-        return 0;
-    }
-
-    @Override
-    public boolean isSelectedIndex(int index) {
-        return false;
-    }
-
-    @Override
-    public int getAnchorSelectionIndex() {
-        return 0;
-    }
-
-    @Override
-    public void setAnchorSelectionIndex(int index) {        
-    }
-
-    @Override
-    public int getLeadSelectionIndex() {
-        return -1;
-    }
-
-    @Override
-    public void setLeadSelectionIndex(int index) {
-    }
-
-    @Override
-    public void clearSelection() {
-    }
-
-    @Override
-    public boolean isSelectionEmpty() {
-        return true;
-    }
-
-    @Override
-    public void insertIndexInterval(int index, int length, boolean before) {
-    }
-
-    @Override
-    public void removeIndexInterval(int index0, int index1) {
-    }
-
-    @Override
-    public void setValueIsAdjusting(boolean valueIsAdjusting) {
-    }
-
-    @Override
-    public boolean getValueIsAdjusting() {
-        return false;
-    }
-
-    @Override
-    public void setSelectionMode(int selectionMode) {
-    }
-
-    @Override
-    public int getSelectionMode() {
-        return -1;
-    }
-
-    @Override
-    public void addListSelectionListener(ListSelectionListener x) {        
-    }
-
-    @Override
-    public void removeListSelectionListener(ListSelectionListener x) {
-    }
-
-}
Binary file client/swing-components/src/main/resources/icons/resize-grip.png has changed
--- a/client/swing-components/src/main/resources/icons/resize-grip.svg	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="13"
-   height="13"
-   id="svg17653"
-   version="1.1"
-   inkscape:version="0.48.2 r9819"
-   sodipodi:docname="resize-grip.svg">
-  <defs
-     id="defs17655" />
-  <sodipodi:namedview
-     id="base"
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1.0"
-     inkscape:pageopacity="0.0"
-     inkscape:pageshadow="2"
-     inkscape:zoom="21.311078"
-     inkscape:cx="-8.2186936"
-     inkscape:cy="8.0008486"
-     inkscape:current-layer="layer1"
-     showgrid="true"
-     inkscape:grid-bbox="true"
-     inkscape:document-units="px"
-     inkscape:window-width="1920"
-     inkscape:window-height="1022"
-     inkscape:window-x="0"
-     inkscape:window-y="26"
-     inkscape:window-maximized="1" />
-  <metadata
-     id="metadata17658">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-        <dc:title />
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <g
-     id="layer1"
-     inkscape:label="Layer 1"
-     inkscape:groupmode="layer"
-     transform="translate(0,-3)">
-    <path
-       transform="matrix(0.65777374,0,0,0.65777374,-560.57081,-392.19484)"
-       d="m 870.53682,617.14966 a 1.9003495,1.9003495 0 1 1 -3.80069,0 1.9003495,1.9003495 0 1 1 3.80069,0 z"
-       sodipodi:ry="1.9003495"
-       sodipodi:rx="1.9003495"
-       sodipodi:cy="617.14966"
-       sodipodi:cx="868.63647"
-       id="path5513"
-       style="fill:#b9beb3;fill-opacity:1;stroke:none;display:inline;enable-background:new"
-       sodipodi:type="arc" />
-    <path
-       sodipodi:type="arc"
-       style="fill:#b9beb3;fill-opacity:1;stroke:none;display:inline;enable-background:new"
-       id="path5515"
-       sodipodi:cx="868.63647"
-       sodipodi:cy="617.14966"
-       sodipodi:rx="1.9003495"
-       sodipodi:ry="1.9003495"
-       d="m 870.53682,617.14966 a 1.9003495,1.9003495 0 1 1 -3.80069,0 1.9003495,1.9003495 0 1 1 3.80069,0 z"
-       transform="matrix(0.65777374,0,0,0.65777374,-563.84354,-392.19484)" />
-    <path
-       sodipodi:type="arc"
-       style="fill:#b9beb3;fill-opacity:1;stroke:none;display:inline;enable-background:new"
-       id="path5517"
-       sodipodi:cx="868.63647"
-       sodipodi:cy="617.14966"
-       sodipodi:rx="1.9003495"
-       sodipodi:ry="1.9003495"
-       d="m 870.53682,617.14966 a 1.9003495,1.9003495 0 1 1 -3.80069,0 1.9003495,1.9003495 0 1 1 3.80069,0 z"
-       transform="matrix(0.65777374,0,0,0.65777374,-560.57081,-395.46756)" />
-    <path
-       transform="matrix(0.65777374,0,0,0.65777374,-560.57081,-398.74029)"
-       d="m 870.53682,617.14966 a 1.9003495,1.9003495 0 1 1 -3.80069,0 1.9003495,1.9003495 0 1 1 3.80069,0 z"
-       sodipodi:ry="1.9003495"
-       sodipodi:rx="1.9003495"
-       sodipodi:cy="617.14966"
-       sodipodi:cx="868.63647"
-       id="path5519"
-       style="fill:#b9beb3;fill-opacity:1;stroke:none;display:inline;enable-background:new"
-       sodipodi:type="arc" />
-    <path
-       transform="matrix(0.65777374,0,0,0.65777374,-567.11626,-392.19484)"
-       d="m 870.53682,617.14966 a 1.9003495,1.9003495 0 1 1 -3.80069,0 1.9003495,1.9003495 0 1 1 3.80069,0 z"
-       sodipodi:ry="1.9003495"
-       sodipodi:rx="1.9003495"
-       sodipodi:cy="617.14966"
-       sodipodi:cx="868.63647"
-       id="path5521"
-       style="fill:#b9beb3;fill-opacity:1;stroke:none;display:inline;enable-background:new"
-       sodipodi:type="arc" />
-    <path
-       transform="matrix(0.65777374,0,0,0.65777374,-563.84354,-395.46756)"
-       d="m 870.53682,617.14966 a 1.9003495,1.9003495 0 1 1 -3.80069,0 1.9003495,1.9003495 0 1 1 3.80069,0 z"
-       sodipodi:ry="1.9003495"
-       sodipodi:rx="1.9003495"
-       sodipodi:cy="617.14966"
-       sodipodi:cx="868.63647"
-       id="path5523"
-       style="fill:#b9beb3;fill-opacity:1;stroke:none;display:inline;enable-background:new"
-       sodipodi:type="arc" />
-  </g>
-</svg>
Binary file client/swing-components/src/main/resources/icons/scale-slider-vert-backdrop.png has changed
Binary file client/swing-components/src/main/resources/icons/scale-slider-vert.png has changed
--- a/client/swing-components/src/test/java/com/redhat/thermostat/swing/EdtHelperTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,196 +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.swing;
-
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
-import java.awt.EventQueue;
-import java.lang.reflect.InvocationTargetException;
-import java.util.concurrent.Callable;
-
-import javax.swing.SwingUtilities;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.swing.EdtHelper;
-
-public class EdtHelperTest {
-
-    private class ExceptionCallable implements Callable<Object>  {
-
-        @Override
-        public Object call() throws Exception {
-            throw new Exception("fluff");
-        }
-        
-    }
-
-    private class ResultCallable implements Callable<Object> {
-    
-        private Object result;
-        private ResultCallable(Object r) {
-            result = r;
-        }
-        @Override
-        public Object call() throws Exception {
-            // By waiting here, we make sure the EDTHelper actually waits for the call.
-            try {
-                Thread.sleep(100);
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-            if (EventQueue.isDispatchThread()) {
-                calledOnEDT = true;
-            }
-            return result;
-        }
-        
-    }
-
-    private class TestRunnable implements Runnable {
-
-        @Override
-        public void run() {
-            // By waiting here, we make sure the EDTHelper actually waits for the call.
-            try {
-                Thread.sleep(100);
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-            }
-            if (EventQueue.isDispatchThread()) {
-                calledOnEDT = true;
-            }
-        }
-        
-    }
-
-    private volatile boolean calledOnEDT;
-
-    @Before
-    public void setUp() {
-        calledOnEDT = false;
-    }
-
-    @After
-    public void tearDown() {
-        calledOnEDT = false;
-    }
-
-    @Test
-    public void testCallRunnableFromNonEDT() throws InvocationTargetException, InterruptedException {
-        Runnable r = new TestRunnable();
-        new EdtHelper().callAndWait(r);
-        assertTrue(calledOnEDT);
-    }
-
-    @Test
-    public void testCallRunnableFromEDT() throws InvocationTargetException, InterruptedException {
-        final Runnable r = new TestRunnable();
-        SwingUtilities.invokeAndWait(new Runnable() {
-            
-            @Override
-            public void run() {
-                try {
-                    new EdtHelper().callAndWait(r);
-                } catch (InvocationTargetException e) {
-                    throw new RuntimeException(e);
-                } catch (InterruptedException e) {
-                    Thread.currentThread().interrupt();
-                }
-            }
-        });
-        assertTrue(calledOnEDT);
-    }
-
-    @Test
-    public void testCallCallableFromNoEDT() throws InvocationTargetException, InterruptedException {
-        final Object expected = new Object();
-        Callable<Object> c = new ResultCallable(expected);
-        Object result = new EdtHelper().callAndWait(c);
-        assertTrue(calledOnEDT);
-        assertSame(expected, result);
-    }
-
-    @Test
-    public void testCallCallableFromEDT() throws InvocationTargetException, InterruptedException {
-        final Object expected = new Object();
-        final Callable<Object> c = new ResultCallable(expected);
-        final Object[] result = new Object[1];
-        SwingUtilities.invokeAndWait(new Runnable() {
-            
-            @Override
-            public void run() {
-                try {
-                    result[0] = new EdtHelper().callAndWait(c);
-                } catch (InvocationTargetException | InterruptedException e) {
-                    throw new RuntimeException();
-                }
-            }
-        });
-        assertTrue(calledOnEDT);
-        assertSame(expected, result[0]);
-    }
-
-    @Test(expected=InvocationTargetException.class)
-    public void testCallCallableFromNoEDTThrowingException() throws InvocationTargetException, InterruptedException {
-        Callable<Object> c = new ExceptionCallable();
-        new EdtHelper().callAndWait(c);
-    }
-
-    @Test
-    public void testCallCallableFromEDTThrowingException() throws InvocationTargetException, InterruptedException {
-        final boolean[] exceptionThrown = new boolean[1];
-        final Callable<Object> c = new ExceptionCallable();
-        SwingUtilities.invokeAndWait(new Runnable() {
-            
-            @Override
-            public void run() {
-                try {
-                    new EdtHelper().callAndWait(c);
-                } catch (InvocationTargetException e) {
-                    exceptionThrown[0] = true;
-                } catch (InterruptedException e) {
-                    Thread.currentThread().interrupt();
-                }
-            }
-        });
-        assertTrue(exceptionThrown[0]);
-    }
-}
--- a/client/swing-components/src/test/java/com/redhat/thermostat/swing/StatusBarTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +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.swing;
-
-import static org.junit.Assert.*;
-
-import java.awt.BorderLayout;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.util.concurrent.Semaphore;
-
-import javax.swing.JFrame;
-
-import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
-
-import org.fest.swing.annotation.GUITest;
-import org.fest.swing.annotation.RunsInEDT;
-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.JLabelFixture;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(CacioFESTRunner.class)
-public class StatusBarTest {
-
-    private JFrame frame;
-    private FrameFixture frameFixture;
-    
-    private StatusBar statusBar;
-    
-    @BeforeClass
-    public static void setUpOnce() {
-        FailOnThreadViolationRepaintManager.install();
-    }
-    
-    @Before
-    public void setUp() {
-        GuiActionRunner.execute(new GuiTask() {
-            @Override
-            protected void executeInEDT() throws Throwable {
-                frame = new JFrame();
-                frame.getContentPane().setLayout(new BorderLayout());
-                
-                statusBar = new StatusBar();
-                frame.getContentPane().add(statusBar, BorderLayout.SOUTH);
-                
-                frame.setSize(500, 500);
-            }
-        });
-        frameFixture = new FrameFixture(frame);
-    }
-    
-    @After
-    public void tearDown() {
-        frameFixture.cleanUp();
-        frameFixture = null;
-    }
-    
-    @Test
-    @GUITest
-    @RunsInEDT
-    public void testSetPrimaryStatusLabel() throws InterruptedException {
-        frameFixture.show();
-        
-        JLabelFixture labelfixture = frameFixture.label("primaryStatusLabel");
-        labelfixture.requireText("");
-        
-        final Semaphore sem = new Semaphore(0);
-        GuiActionRunner.execute(new GuiTask() {
-            @Override
-            protected void executeInEDT() throws Throwable {
-                statusBar.setPrimaryStatus("test");
-                sem.release();
-            }
-        });
-        sem.acquire();
-        
-        // the label has an extra space at the beginning
-        labelfixture.requireText(" test");
-    }
-    
-    @Test
-    @GUITest
-    @RunsInEDT
-    public void testSetPrimaryStatusLabelWithProperty() throws InterruptedException {
-        frameFixture.show();
-        
-        final String[] primaryStatus = new String[2];
-        
-        final Semaphore sem = new Semaphore(2);
-        statusBar.addPropertyChangeListener(StatusBar.PRIMARY_STATUS_PROPERTY,
-                                                      new PropertyChangeListener()
-        {
-            @Override
-            public void propertyChange(PropertyChangeEvent evt) {
-                primaryStatus[0] = (String) evt.getOldValue();
-                primaryStatus[1] = (String) evt.getNewValue();
-                sem.release();
-            }
-        });
-        
-        GuiActionRunner.execute(new GuiTask() {
-            @Override
-            protected void executeInEDT() throws Throwable {
-                statusBar.setPrimaryStatus("test");
-                sem.release();
-            }
-        });
-        sem.acquire(2);
-        
-        assertEquals("", primaryStatus[0]);
-        assertEquals("test", primaryStatus[1]);
-    }
-}
--- a/client/swing-components/src/test/java/com/redhat/thermostat/swing/models/LongRangeNormalizerTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +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.swing.models;
-
-import static org.junit.Assert.*;
-import junit.framework.Assert;
-
-import org.junit.Test;
-
-public class LongRangeNormalizerTest {
-
-    @Test
-    public void testSameRange() {
-        
-        LongRange range = new LongRange();
-        range.setMax(10);
-        range.setMin(0);
-        
-        LongRangeNormalizer model = new LongRangeNormalizer(range);
-        
-        model.setValue(5);
-        
-        model.setMaxNormalized(10);
-        model.setMinNormalized(0);
-        
-        
-        Assert.assertEquals((int) model.getValue(), model.getValueNormalized());
-    }
-
-    @Test
-    public void testDoubleRange() {
-        
-        LongRange range = new LongRange();
-        range.setMax(10);
-        range.setMin(0);
-        
-        LongRangeNormalizer model = new LongRangeNormalizer(range);
-        
-        model.setValue(5);
-        
-        model.setMaxNormalized(20);
-        model.setMinNormalized(0);
-        
-        
-        Assert.assertEquals(10, model.getValueNormalized());
-    }
-    
-    @Test
-    public void testRanges() {
-        
-        LongRange range = new LongRange();
-        range.setMax(10);
-        range.setMin(0);
-        
-        LongRangeNormalizer model = new LongRangeNormalizer(range);
-        
-        model.setValue(5);
-        
-        model.setMaxNormalized(40);
-        model.setMinNormalized(0);
-                
-        Assert.assertEquals(20, model.getValueNormalized());
-        
-        model.setMaxNormalized(60);
-        model.setMinNormalized(0);
-                
-        Assert.assertEquals(30, model.getValueNormalized());
-                
-        model.setMaxNormalized(200);
-        model.setMinNormalized(100);
-                
-        Assert.assertEquals(150, model.getValueNormalized());
-        
-        range.setMax(100);
-        range.setMin(0);
-        model.setValue(50);
-        
-        model.setMaxNormalized(1);
-        model.setMinNormalized(0);
-                
-        Assert.assertEquals(1, model.getValueNormalized());
-        
-        model.setValue(49);
-        Assert.assertEquals(0, model.getValueNormalized());
-    }
-}
--- a/client/swing-components/src/test/java/com/redhat/thermostat/swing/models/NullSelectionModelTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.swing.models;
-
-import static org.junit.Assert.*;
-
-import javax.swing.DefaultListModel;
-import javax.swing.JFrame;
-import javax.swing.JList;
-
-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.junit.After;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(CacioFESTRunner.class)
-public class NullSelectionModelTest {
-
-    private JFrame frame;
-    private FrameFixture frameFixture;
-    private JList<String> list;
-    
-    @BeforeClass
-    public static void setUpOnce() {
-        FailOnThreadViolationRepaintManager.install();
-    }
-    
-    @Before
-    public void setUp() {
-        GuiActionRunner.execute(new GuiTask() {
-            @Override
-            protected void executeInEDT() throws Throwable {
-                frame = new JFrame();
-                
-                DefaultListModel<String> model = new DefaultListModel<>();
-                
-                model.addElement("fluff #1");
-                model.addElement("fluff #2");
-                model.addElement("fluff #3");
-                model.addElement("fluff #4");
-                model.addElement("fluff #5");
-
-                list = new JList<>(model);
-                list.setSelectionModel(new NullSelectionModel());
-                
-                frame.add(list);
-            }
-        });
-        frameFixture = new FrameFixture(frame);
-    }
-    
-    @After
-    public void tearDown() {
-        frameFixture.cleanUp();
-        frameFixture = null;
-    }
-    
-    @GUITest
-    @Test
-    public void testCellNotSelectable() {
-        frameFixture.show();
-        
-        String[] selection = frameFixture.list().selection();
-        assertEquals(0, selection.length);
-        frameFixture.list().clickItem(2);
-        selection = frameFixture.list().selection();
-        assertEquals(0, selection.length);
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,167 @@
+<?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-swing</artifactId>
+  <packaging>bundle</packaging>
+
+  <name>Thermostat Swing Client</name>
+
+  <dependencies>
+      <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-client-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-laf</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <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.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>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.jfree</groupId>
+      <artifactId>jfreechart</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>true</filtering>
+        <excludes>
+          <exclude>**/*.png</exclude>
+        </excludes>
+      </resource>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>false</filtering>
+        <includes>
+          <include>**/*.png</include>
+        </includes>
+      </resource>
+    </resources>
+
+    <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.swing.internal.osgi.ThermostatActivator</Bundle-Activator>
+            <Bundle-SymbolicName>com.redhat.thermostat.client.swing</Bundle-SymbolicName>
+            <Export-Package>
+              com.redhat.thermostat.client.swing,
+              com.redhat.thermostat.client.swing.components,
+              com.redhat.thermostat.client.swing.components.models,
+              com.redhat.thermostat.client.swing.views,
+            </Export-Package>
+            <Private-Package>
+              com.redhat.thermostat.client.swing.internal,
+              com.redhat.thermostat.client.swing.internal.components,
+              com.redhat.thermostat.client.swing.internal.osgi,
+              com.redhat.thermostat.client.swing.internal.config
+            </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/client/swing/src/main/java/com/redhat/thermostat/client/swing/IconResource.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,93 @@
+/*
+ * 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.swing;
+
+import java.io.File;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+
+public class IconResource {
+    /* FIXME we need to pick up the icons dynamically */
+
+    private static final String ICON_PREFIX = "/usr/share/icons/gnome/";
+
+    // an icon that should always be available and indicate that the actual icon
+    // is missing.
+    public static final IconResource MISSING_ICON = null;
+
+    public static final IconResource JAVA_APPLICATION = new IconResource("duke.png");
+    public static final IconResource HOST = new IconResource(ICON_PREFIX + "16x16/devices/computer.png");
+    
+    public static final IconResource ERROR = new IconResource(ICON_PREFIX + "48x48/status/dialog-error.png");
+    public static final IconResource QUESTION = new IconResource(ICON_PREFIX + "48x48/status/dialog-question.png");
+    public static final IconResource WARNING = new IconResource(ICON_PREFIX + "48x48/status/dialog-warning.png");
+
+    public static final IconResource COMPUTER = new IconResource(ICON_PREFIX + "48x48/devices/computer.png");
+    public static final IconResource NETWORK_SERVER = new IconResource(ICON_PREFIX + "48x48/places/network-server.png");
+    public static final IconResource NETWORK_GROUP = new IconResource(ICON_PREFIX + "48x48/places/network-workgroup.png");
+
+    public static final IconResource ARROW_RIGHT = new IconResource(ICON_PREFIX + "48x48/actions/go-next.png");
+
+    public static final IconResource SEARCH = new IconResource(ICON_PREFIX + "16x16/actions/search.png");
+
+    private final String path;
+
+    private IconResource(String descriptor) {
+        this.path = descriptor;
+    }
+
+    public static IconResource fromPath(String path) {
+        // TODO implement this
+        return null;
+    }
+
+    public Icon getIcon() {
+        if (new File(path).exists()) {
+            return new ImageIcon(path);
+        }
+        return null;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public String getUrl() {
+        return "file:" + getPath();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/LayoutDebugHelper.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Window;
+
+import javax.swing.BorderFactory;
+import javax.swing.JComponent;
+
+/**
+ * This class goes through the swing container hierarchy and adds random colored
+ * borders to the components themselves. it makes it easier to see what the
+ * {@code LayoutManager}s are doing
+ */
+public class LayoutDebugHelper {
+
+    private Color[] colors = new Color[] { Color.BLACK, Color.BLUE, Color.CYAN, Color.GREEN, Color.MAGENTA, Color.PINK, Color.ORANGE, Color.RED, Color.YELLOW };
+    private int colorIndex = 0;
+
+    public void debugLayout(Window w) {
+        Component[] children = w.getComponents();
+        debugLayout(children);
+    }
+
+    public void debugLayout(Component c) {
+        if (c instanceof JComponent) {
+            JComponent panel = (JComponent) c;
+            try {
+                panel.setBorder(BorderFactory.createLineBorder(colors[colorIndex % colors.length]));
+            } catch (IllegalArgumentException iae) {
+                // never mind then
+            }
+            colorIndex++;
+            debugLayout(panel.getComponents());
+        }
+    }
+
+    public void debugLayout(Component[] components) {
+        for (Component aComponent : components) {
+            debugLayout(aComponent);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/MainWindow.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,795 @@
+/*
+ * 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.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.image.BufferedImage;
+import java.io.PrintStream;
+import java.lang.reflect.InvocationTargetException;
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+import javax.swing.BorderFactory;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTree;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+import javax.swing.SwingWorker;
+import javax.swing.ToolTipManager;
+import javax.swing.event.TreeExpansionEvent;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.event.TreeWillExpandListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.ExpandVetoException;
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+
+import sun.misc.Signal;
+
+import com.redhat.thermostat.client.core.HostFilter;
+import com.redhat.thermostat.client.core.VmFilter;
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.core.views.SearchFieldView.SearchAction;
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.osgi.service.HostDecorator;
+import com.redhat.thermostat.client.osgi.service.MenuAction;
+import com.redhat.thermostat.client.osgi.service.VMContextAction;
+import com.redhat.thermostat.client.osgi.service.VmDecorator;
+import com.redhat.thermostat.client.swing.components.EdtHelper;
+import com.redhat.thermostat.client.swing.components.HtmlTextBuilder;
+import com.redhat.thermostat.client.swing.components.StatusBar;
+import com.redhat.thermostat.client.swing.internal.MainView;
+import com.redhat.thermostat.client.swing.internal.components.DecoratedDefaultMutableTreeNode;
+import com.redhat.thermostat.client.swing.views.SearchFieldSwingView;
+import com.redhat.thermostat.client.ui.Decorator;
+import com.redhat.thermostat.client.ui.IconDescriptor;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ActionNotifier;
+import com.redhat.thermostat.common.HostsVMsLoader;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.Ref;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.StringUtils;
+
+public class MainWindow extends JFrame implements MainView {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    /**
+     * Updates a TreeModel in the background in an Swing EDT-safe manner.
+     */
+    private static class BackgroundTreeModelWorker extends SwingWorker<DefaultMutableTreeNode, Void> {
+
+        private JTree tree;
+
+        private final DefaultTreeModel treeModel;
+        private DefaultMutableTreeNode treeRoot;
+        
+        private List<HostFilter> hostFilters;
+        private List<VmFilter> vmFilters;
+        private List<HostDecorator> hostDecorators;
+        private List<VmDecorator> vmDecorators;
+        
+        private HostsVMsLoader hostsVMsLoader;
+
+        public BackgroundTreeModelWorker(DefaultTreeModel model, DefaultMutableTreeNode root,
+                                         List<HostFilter> hostFilters, List<VmFilter> vmFilters,
+                                         List<HostDecorator> hostDecorators, List<VmDecorator> vmDecorators,
+                                         HostsVMsLoader hostsVMsLoader, JTree tree)
+        {
+            this.hostFilters = hostFilters;
+            this.vmFilters = vmFilters;
+
+            this.vmDecorators = vmDecorators;
+            this.hostDecorators = hostDecorators;
+
+            this.treeModel = model;
+            this.treeRoot = root;
+            this.hostsVMsLoader = hostsVMsLoader;
+            this.tree = tree;
+        }
+
+        @Override
+        protected DefaultMutableTreeNode doInBackground() throws Exception {
+            DefaultMutableTreeNode root = new DefaultMutableTreeNode();
+            
+            Collection<HostRef> hostsInRemoteModel = hostsVMsLoader.getHosts();
+            buildHostSubTree(root, hostsInRemoteModel);
+            return root;
+        }
+
+        private boolean buildHostSubTree(DefaultMutableTreeNode parent, Collection<HostRef> objectsInRemoteModel) {
+            boolean subTreeMatches = false;
+            for (HostRef inRemoteModel : objectsInRemoteModel) {
+                DecoratedDefaultMutableTreeNode inTreeNode =
+                        new DecoratedDefaultMutableTreeNode(inRemoteModel);
+
+                boolean shouldInsert = false;
+                if (hostFilters == null) {
+                    shouldInsert = true;
+                } else {
+                    shouldInsert = true;
+                    for (HostFilter filter : hostFilters) {
+                        if (!filter.matches(inRemoteModel)) {
+                            shouldInsert = false;
+                            break;
+                        }
+                    }
+                }
+                
+                Collection<VmRef> children = hostsVMsLoader.getVMs(inRemoteModel);
+                boolean subtreeResult = buildVmSubTree(inTreeNode, children);
+                if (subtreeResult) {
+                    shouldInsert = true;
+                }
+
+                if (shouldInsert) {
+                    for (HostDecorator decorator : hostDecorators) {
+                        HostFilter filter = decorator.getFilter();
+                        if (filter != null && filter.matches(inRemoteModel)) {
+                            inTreeNode.addDecorator(decorator.getDecorator());
+                        }
+                    }
+                    
+                    parent.add(inTreeNode);
+                    subTreeMatches = true;
+                }
+            }
+            
+            return subTreeMatches;
+        }
+
+        private boolean buildVmSubTree(DefaultMutableTreeNode parent, Collection<VmRef> objectsInRemoteModel) {
+            boolean subTreeMatches = false;
+            for (VmRef inRemoteModel : objectsInRemoteModel) {
+                DecoratedDefaultMutableTreeNode inTreeNode =
+                        new DecoratedDefaultMutableTreeNode(inRemoteModel);
+
+                boolean shouldInsert = false;
+                if (vmFilters == null) {
+                    shouldInsert = true;
+                } else {
+                    shouldInsert = true;
+                    for (VmFilter filter : vmFilters) {
+                        if (!filter.matches(inRemoteModel)) {
+                            shouldInsert = false;
+                            break;
+                        }
+                    }
+                }
+
+                if (shouldInsert) {
+                    for (VmDecorator decorator : vmDecorators) {
+                        VmFilter filter = decorator.getFilter();
+                        if (filter != null && filter.matches(inRemoteModel)) {
+                            inTreeNode.addDecorator(decorator.getDecorator());
+                        }
+                    }
+
+                    parent.add(inTreeNode);
+                    subTreeMatches = true;
+                }
+            }
+
+            return subTreeMatches;
+        }
+
+        @Override
+        protected void done() {
+            DefaultMutableTreeNode sourceRoot;
+            try {
+                sourceRoot = get();
+                syncTree(sourceRoot, treeModel, treeRoot);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            } catch (ExecutionException e) {
+                e.printStackTrace();
+            }
+        }
+
+        private void syncTree(DefaultMutableTreeNode sourceRoot, DefaultTreeModel targetModel, DefaultMutableTreeNode targetNode) {
+            
+            @SuppressWarnings("unchecked") // We know what we put into these trees.
+            List<DefaultMutableTreeNode> sourceChildren = Collections.list(sourceRoot.children());
+
+            @SuppressWarnings("unchecked")
+            List<DefaultMutableTreeNode> targetChildren = Collections.list(targetNode.children());
+            for (DefaultMutableTreeNode sourceChild : sourceChildren) {
+                Ref sourceRef = (Ref) sourceChild.getUserObject();
+                DefaultMutableTreeNode targetChild = null;
+                for (DefaultMutableTreeNode aChild : targetChildren) {
+                    Ref targetRef = (Ref) aChild.getUserObject();
+                    if (targetRef.equals(sourceRef)) {
+                        targetChild = aChild;
+                        if (sourceChild instanceof DecoratedDefaultMutableTreeNode) {
+                            DecoratedDefaultMutableTreeNode source = (DecoratedDefaultMutableTreeNode) sourceChild;
+                            ((DecoratedDefaultMutableTreeNode) targetChild).setDecorators(source.getDecorators());
+                        }
+                        break;
+                    }
+                }
+
+                if (targetChild == null) {
+                    targetChild = new DecoratedDefaultMutableTreeNode(sourceRef);
+                    if (sourceChild instanceof DecoratedDefaultMutableTreeNode) {
+                        DecoratedDefaultMutableTreeNode source = (DecoratedDefaultMutableTreeNode) sourceChild;
+                        ((DecoratedDefaultMutableTreeNode) targetChild).setDecorators(source.getDecorators());
+                    }
+                    targetModel.insertNodeInto(targetChild, targetNode, targetNode.getChildCount());
+                }
+
+                syncTree(sourceChild, targetModel, targetChild);
+            }
+
+            for (DefaultMutableTreeNode targetChild : targetChildren) {
+                Ref targetRef = (Ref) targetChild.getUserObject();
+                boolean matchFound = false;
+                for (DefaultMutableTreeNode sourceChild : sourceChildren) {
+                    Ref sourceRef = (Ref) sourceChild.getUserObject();
+                    if (targetRef.equals(sourceRef)) {
+                        matchFound = true;
+                        break;
+                    }
+                }
+
+                if (!matchFound) {
+                    targetModel.removeNodeFromParent(targetChild);
+                }
+            }
+            ensureRootIsExpanded(targetModel);
+        }
+
+        private void ensureRootIsExpanded(final DefaultTreeModel model) {
+            DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
+            tree.expandPath(new TreePath(root.getPath()));
+        }
+
+    }
+
+    private static final long serialVersionUID = 5608972421496808177L;
+
+    private final JMenuBar mainMenuBar = new JMenuBar();
+    private final MenuHelper mainMenuHelper = new MenuHelper(mainMenuBar);
+    private JPanel contentArea = null;
+
+    private SearchFieldSwingView searchField = new SearchFieldSwingView();
+    private JTree agentVmTree = null;
+
+    private final ShutdownClient shutdownAction;
+
+    private ActionNotifier<Action> actionNotifier = new ActionNotifier<>(this);
+
+    private JPopupMenu vmContextMenu;
+    private StatusBar statusBar;
+    
+    private final DefaultMutableTreeNode publishedRoot =
+            new DefaultMutableTreeNode(translator.localize(LocaleResources.MAIN_WINDOW_TREE_ROOT_NAME));
+    private final DefaultTreeModel publishedTreeModel = new DefaultTreeModel(publishedRoot);
+
+    @SuppressWarnings("restriction")
+    public MainWindow() {
+        super();
+
+        shutdownAction = new ShutdownClient();
+
+        searchField.addActionListener(new ActionListener<SearchAction>() {
+            @Override
+            public void actionPerformed(ActionEvent<SearchAction> actionEvent) {
+                switch (actionEvent.getActionId()) {
+                case TEXT_CHANGED:
+                    fireViewAction(Action.HOST_VM_TREE_FILTER);
+                    break;
+                }
+            }
+        });
+        agentVmTree = new JTree(publishedTreeModel);
+        agentVmTree.setName("agentVmTree");
+        agentVmTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+        agentVmTree.setCellRenderer(new AgentVmTreeCellRenderer());
+        agentVmTree.addTreeWillExpandListener(new TreeWillExpandListener() {
+            @Override
+            public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
+                /* Yup, tree will expand */
+            }
+
+            @Override
+            public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
+                if (new TreePath(publishedRoot.getPath()).equals(event.getPath())) {
+                    throw new ExpandVetoException(event, "root cant be collapsed");
+                }
+            }
+        });
+        ToolTipManager.sharedInstance().registerComponent(agentVmTree);
+        contentArea = new JPanel(new BorderLayout());
+
+        setupMenus();
+        setupPanels();
+
+        this.setPreferredSize(new Dimension(800, 600));
+
+        agentVmTree.setSelectionPath(new TreePath(((DefaultMutableTreeNode) publishedTreeModel.getRoot()).getPath()));
+        
+        //agentVmTree.setLargeModel(true);
+        agentVmTree.setRowHeight(25);
+        
+        statusBar = new StatusBar();
+        getContentPane().add(statusBar, BorderLayout.SOUTH);
+        
+        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+        addWindowListener(shutdownAction);
+
+        // Handle SIGTERM/SIGINT properly
+        Signal.handle(new Signal("TERM"), shutdownAction);
+        Signal.handle(new Signal("INT"), shutdownAction);
+        
+        addComponentListener(new ComponentAdapter() {
+
+            @Override
+            public void componentShown(ComponentEvent e) {
+                fireViewAction(Action.VISIBLE);
+            }
+
+            @Override
+            public void componentHidden(ComponentEvent e) {
+                fireViewAction(Action.HIDDEN);
+            }
+        });
+
+    }
+
+    private void setupMenus() {
+
+        JMenu fileMenu = new JMenu(translator.localize(LocaleResources.MENU_FILE));
+        fileMenu.getPopupMenu().setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1));
+        mainMenuBar.add(fileMenu);
+
+        JMenuItem fileExitMenu = new JMenuItem(translator.localize(LocaleResources.MENU_FILE_EXIT));
+        fileExitMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, InputEvent.CTRL_DOWN_MASK));
+        fileExitMenu.addActionListener(shutdownAction);
+        fileMenu.add(fileExitMenu);
+
+        JMenu editMenu = new JMenu(translator.localize(LocaleResources.MENU_EDIT));
+        mainMenuBar.add(editMenu);
+
+        JMenuItem configureClientMenuItem = new JMenuItem(translator.localize(LocaleResources.MENU_EDIT_CONFIGURE_CLIENT));
+        configureClientMenuItem.setName("showClientConfig");
+        configureClientMenuItem.addActionListener(new java.awt.event.ActionListener() {
+            @Override
+            public void actionPerformed(java.awt.event.ActionEvent e) {
+                fireViewAction(Action.SHOW_CLIENT_CONFIG);
+            }
+        });
+        editMenu.add(configureClientMenuItem);
+
+        editMenu.addSeparator();
+        JMenuItem historyModeMenuItem = new JCheckBoxMenuItem(translator.localize(LocaleResources.MENU_EDIT_ENABLE_HISTORY_MODE));
+        historyModeMenuItem.setName("historyModeSwitch");
+        historyModeMenuItem.setSelected(false);
+        historyModeMenuItem.addActionListener(new java.awt.event.ActionListener() {
+            @Override
+            public void actionPerformed(java.awt.event.ActionEvent e) {
+                fireViewAction(Action.SWITCH_HISTORY_MODE);
+            }
+        });
+        editMenu.add(historyModeMenuItem);
+
+        JMenu viewMenu = new JMenu(translator.localize(LocaleResources.MENU_VIEW));
+        mainMenuBar.add(viewMenu);
+        JMenuItem configureAgentMenuItem = new JMenuItem(translator.localize(LocaleResources.MENU_VIEW_AGENTS));
+        configureAgentMenuItem.setName("showAgentConfig");
+        configureAgentMenuItem.addActionListener(new java.awt.event.ActionListener() {
+            @Override
+            public void actionPerformed(java.awt.event.ActionEvent e) {
+                fireViewAction(Action.SHOW_AGENT_CONFIG);
+            }
+        });
+        viewMenu.add(configureAgentMenuItem);
+
+        JMenu helpMenu = new JMenu(translator.localize(LocaleResources.MENU_HELP));
+        helpMenu.getPopupMenu().setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1));
+        mainMenuBar.add(helpMenu);
+
+        JMenuItem helpAboutMenu = new JMenuItem(translator.localize(LocaleResources.MENU_HELP_ABOUT));
+        helpAboutMenu.addActionListener(new java.awt.event.ActionListener() {
+            @Override
+            public void actionPerformed(java.awt.event.ActionEvent e) {
+                fireViewAction(Action.SHOW_ABOUT_DIALOG);
+            }
+        });
+        helpMenu.add(helpAboutMenu);
+        setJMenuBar(mainMenuBar);
+    }
+
+    private void setupPanels() {
+        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
+        splitPane.setOneTouchExpandable(true);
+        
+        JPanel navigationPanel = new JPanel(new BorderLayout());
+
+        navigationPanel.add(searchField, BorderLayout.PAGE_START);
+
+        agentVmTree.addTreeSelectionListener(new TreeSelectionListener() {
+            @Override
+            public void valueChanged(TreeSelectionEvent e) {
+                if (e.isAddedPath()) {
+                    fireViewAction(Action.HOST_VM_SELECTION_CHANGED);
+                }
+            }
+        });
+        registerContextActionListener(agentVmTree);
+        
+        JScrollPane treeScrollPane = new JScrollPane(agentVmTree);
+        
+        navigationPanel.add(treeScrollPane);
+
+        JPanel detailsPanel = createDetailsPanel();
+
+        navigationPanel.setMinimumSize(new Dimension(200,500));
+        detailsPanel.setMinimumSize(new Dimension(500, 500));
+
+        splitPane.add(navigationPanel);
+        splitPane.add(detailsPanel);
+
+        getContentPane().add(splitPane);
+    }
+
+    private void registerContextActionListener(JTree agentVmTree2) {
+        vmContextMenu = new JPopupMenu();
+        agentVmTree2.addMouseListener(new MouseAdapter() {
+            @Override
+            public void mousePressed(MouseEvent e) {
+                if (e.isPopupTrigger()) {
+                    Ref ref = getSelectedHostOrVm();
+                    if (ref instanceof VmRef) {
+                        fireViewAction(Action.SHOW_VM_CONTEXT_MENU, e);
+                    }
+                }
+            }
+        });
+    }
+
+    @Override
+    public void showVMContextActions(final List<VMContextAction> actions, final MouseEvent e) {
+        SwingUtilities.invokeLater(new Runnable() {
+
+            @Override
+            public void run() {
+                vmContextMenu.removeAll();
+
+                for (final VMContextAction action: actions) {
+                    JMenuItem contextAction = new JMenuItem();
+                    contextAction.setText(action.getName());
+                    contextAction.setToolTipText(action.getDescription());
+
+                    contextAction.addActionListener(new java.awt.event.ActionListener() {
+                        @Override
+                        public void actionPerformed(java.awt.event.ActionEvent e) {
+                            fireViewAction(Action.VM_CONTEXT_ACTION, action);
+                        }
+                    });
+                    vmContextMenu.add(contextAction);
+                }
+
+                vmContextMenu.show((Component)e.getSource(), e.getX(), e.getY());
+            }
+
+        });
+    }
+    
+    private JPanel createDetailsPanel() {
+        JPanel result = new JPanel(new BorderLayout());
+        result.add(contentArea, BorderLayout.CENTER);
+        return result;
+    }
+
+    @SuppressWarnings("restriction")
+    public class ShutdownClient extends WindowAdapter implements java.awt.event.ActionListener, sun.misc.SignalHandler {
+
+        @Override
+        public void windowClosing(WindowEvent e) {
+            shutdown();
+        }
+
+        @Override
+        public void actionPerformed(java.awt.event.ActionEvent e) {
+            shutdown();
+        }
+        
+        @Override
+        public void handle(Signal arg0) {
+            shutdown();
+        }
+
+        private void shutdown() {
+            dispose();
+            fireViewAction(Action.SHUTDOWN);
+        }
+
+    }
+
+    private static class AgentVmTreeCellRenderer extends DefaultTreeCellRenderer {
+        private static final long serialVersionUID = 4444642511815252481L;
+
+        @Override
+        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
+            
+            Object node = ((DefaultMutableTreeNode) value).getUserObject();
+            setToolTipText(createToolTipText(node));
+            
+            Component component = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
+            if (value instanceof DecoratedDefaultMutableTreeNode) {
+                DecoratedDefaultMutableTreeNode treeNode = (DecoratedDefaultMutableTreeNode) value;
+                setAnnotation(treeNode, node, component);
+            }
+
+            return component;
+        }
+        
+        // TODO: we can cache more, for example the full icon, not just the decoration
+        private Map<Decorator, ImageIcon> decoratorsCache = new HashMap<>();
+        private void setAnnotation(DecoratedDefaultMutableTreeNode treeNode, Object value, Component component) {
+
+            List<Decorator> decorators = treeNode.getDecorators();
+            for (Decorator dec : decorators) {
+                String newText = dec.getLabel(getText());
+                setText(newText);
+                setLabelFor(component);
+                
+                ImageIcon icon = decoratorsCache.get(dec);
+                if (icon == null) {
+                    //System.err.println("cache miss: " + dec);
+                    IconDescriptor iconDescriptor = dec.getIconDescriptor();
+                    if (iconDescriptor != null) {
+                        ByteBuffer data = iconDescriptor.getData();
+                        icon = new ImageIcon(data.array());
+                        decoratorsCache.put(dec, icon);
+                    }
+                }
+                
+                if (icon == null) {
+                    return;
+                }
+                
+                Icon currentIcon = getIcon();
+                switch (dec.getQuadrant()) {
+                case BOTTOM_LEFT:
+                    int y = currentIcon.getIconHeight() - icon.getIconHeight();
+                    paintCustomIcon(currentIcon, icon, y);
+                    break;
+                    
+                case TOP_LEFT:
+                    paintCustomIcon(currentIcon, icon, 0);
+                    break;
+                    
+                case MAIN:
+                default:
+                    setIcon(icon);
+                    break;
+                }
+            }
+        }
+        
+        private void paintCustomIcon(Icon currentIcon, ImageIcon icon, int y) {
+            BufferedImage image = new BufferedImage(currentIcon.getIconWidth(),
+                                                    currentIcon.getIconHeight(),
+                                                    BufferedImage.TYPE_INT_ARGB);
+            Graphics2D graphics = (Graphics2D) image.getGraphics();
+            
+            currentIcon.paintIcon(null, graphics, 0, 0);
+            graphics.drawImage(icon.getImage(), 0, y, null);
+            
+            setIcon(new ImageIcon(image));
+        }
+        
+        private String createToolTipText(Object value) {
+            if (value instanceof HostRef) {
+                HostRef hostRef = (HostRef) value;
+                String hostNameHtml = new HtmlTextBuilder().bold(hostRef.getHostName()).toPartialHtml();
+                String agentIdHtml = new HtmlTextBuilder().bold(hostRef.getAgentId()).toPartialHtml();
+                HtmlTextBuilder builder = new HtmlTextBuilder()
+                    .appendRaw(translator.localize(LocaleResources.TREE_HOST_TOOLTIP_HOST_NAME, hostNameHtml))
+                    .newLine()
+                    .appendRaw(translator.localize(LocaleResources.TREE_HOST_TOOLTIP_AGENT_ID, agentIdHtml));
+                return builder.toHtml();
+            } else if (value instanceof VmRef) {
+                VmRef vmRef = (VmRef) value;
+                String vmNameHtml= new HtmlTextBuilder().bold(vmRef.getName()).toPartialHtml();
+                String vmIdHtml = new HtmlTextBuilder().bold(vmRef.getIdString()).toPartialHtml();
+                HtmlTextBuilder builder = new HtmlTextBuilder()
+                    .appendRaw(translator.localize(LocaleResources.TREE_HOST_TOOLTIP_VM_NAME, vmNameHtml))
+                    .newLine()
+                    .appendRaw(translator.localize(LocaleResources.TREE_HOST_TOOLTIP_VM_ID, vmIdHtml));
+                return builder.toHtml();
+            } else {
+                return null;
+            }
+        }
+    }
+
+    @Override
+    public void addActionListener(ActionListener<Action> l) {
+        actionNotifier.addActionListener(l);
+    }
+
+    public void removeViewActionListener(ActionListener<Action> l) {
+        actionNotifier.removeActionListener(l);
+    }
+
+    private void fireViewAction(Action action) {
+        actionNotifier.fireAction(action);
+    }
+    
+    private void fireViewAction(Action action, Object payload) {
+        actionNotifier.fireAction(action, payload);
+    }
+    
+    @Override
+    public void updateTree(List<HostFilter> hostFilters, List<VmFilter> vmFilters,
+            List<HostDecorator> hostDecorators, List<VmDecorator> vmDecorators,
+            HostsVMsLoader hostsVMsLoader)
+    {
+        BackgroundTreeModelWorker worker =
+                new BackgroundTreeModelWorker(publishedTreeModel, publishedRoot,
+                                              hostFilters, vmFilters, hostDecorators, vmDecorators, hostsVMsLoader, agentVmTree);
+        worker.execute();
+    }
+
+    @SuppressWarnings("unused") // Used for debugging but not in production code.
+    private static void printTree(PrintStream out, TreeNode node, int depth) {
+        out.println(StringUtils.repeat("  ", depth) + node.toString());
+        @SuppressWarnings("unchecked")
+        List<TreeNode> children = Collections.list(node.children());
+        for (TreeNode child : children) {
+            printTree(out, child, depth + 1);
+        }
+    }
+
+    @Override
+    public void setWindowTitle(String title) {
+        setTitle(title);
+    }
+
+    @Override
+    public void showMainWindow() {
+        try {
+            new EdtHelper().callAndWait(new Runnable() {
+
+                @Override
+                public void run() {
+                    pack();
+                    setVisible(true);
+                }
+            });
+        } catch (InvocationTargetException e) {
+            throw new RuntimeException(e);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+        }
+    }
+
+    @Override
+    public void hideMainWindow() {
+        setVisible(false);
+        dispose();
+    }
+
+    @Override
+    public void setStatusBarPrimaryStatus(final String primaryStatus) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                statusBar.setPrimaryStatus(primaryStatus);
+            }
+        });
+    }
+    
+    @Override
+    public void setSubView(final BasicView view) {
+        if (view instanceof SwingComponent) {
+            final SwingComponent swingComp = (SwingComponent)view;
+            SwingUtilities.invokeLater(new Runnable() {
+                @Override
+                public void run() {
+                    contentArea.removeAll();
+                    Component toAdd = swingComp.getUiComponent();
+                    contentArea.add(toAdd);
+                    contentArea.revalidate();
+                }
+            });
+        }
+    }
+
+    @Override
+    public void addMenu(MenuAction action) {
+        mainMenuHelper.addMenuAction(action);
+    }
+
+    @Override
+    public void removeMenu(MenuAction action) {
+        mainMenuHelper.removeMenuAction(action);
+    }
+
+    /**
+     * Returns null to indicate no Ref is selected
+     */
+    @Override
+    public Ref getSelectedHostOrVm() {
+        TreePath path = agentVmTree.getSelectionPath();
+        if (path == null || path.getPathCount() == 1) {
+            return null;
+        }
+        return (Ref) ((DefaultMutableTreeNode) path.getLastPathComponent()).getUserObject();
+    }
+
+    @Override
+    public String getHostVmTreeFilterText() {
+        return searchField.getSearchText();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/MenuHelper.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING. If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code. Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module. An independent module is a module
+ * which is not derived from or based on this code. If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so. If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.swing;
+
+import java.awt.event.ActionEvent;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.logging.Logger;
+
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.JRadioButtonMenuItem;
+import javax.swing.MenuElement;
+
+import com.redhat.thermostat.client.osgi.service.MenuAction;
+import com.redhat.thermostat.client.swing.components.EdtHelper;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.common.utils.StringUtils;
+
+public class MenuHelper {
+
+    private static final Logger logger = LoggingUtils.getLogger(MenuHelper.class);
+
+    private final JMenuBar menuBar;
+
+    public MenuHelper(JMenuBar menuBar) {
+        this.menuBar = menuBar;
+    }
+
+    /**
+     * Add a menu item as specified though the {@link MenuAction} argument.
+     */
+    public void addMenuAction(final MenuAction action) {
+        try {
+            new EdtHelper().callAndWait(new Runnable() {
+                @Override
+                public void run() {
+                    String[] path = action.getPath();
+                    Menu parent = findMenuParent(menuBar, path, true);
+                    JMenuItem menu = null;
+                    switch (action.getType()) {
+                    case RADIO:
+                        menu = new JRadioButtonMenuItem();
+                        break;
+                    case CHECK:
+                        menu = new JCheckBoxMenuItem();
+                        break;
+
+                    case STANDARD:
+                    default:
+                        menu = new JMenuItem();
+                        break;
+                    }
+
+                    menu.setText(action.getName());
+                    menu.addActionListener(new java.awt.event.ActionListener() {
+                        @Override
+                        public void actionPerformed(ActionEvent e) {
+                            action.execute();
+                        }
+                    });
+                    parent.add(new Menu(menu));
+
+                    menuBar.revalidate();
+                }
+            });
+        } catch (InvocationTargetException ite) {
+            Throwable cause = ite.getCause();
+            if (cause instanceof IllegalArgumentException) {
+                throw (IllegalArgumentException) cause;
+            }
+            throw new RuntimeException(cause);
+        } catch (InterruptedException ie) {
+            Thread.currentThread().interrupt();
+            throw new RuntimeException(ie);
+        }
+
+    }
+
+    /**
+     * Remove a existing menu item as specified though the {@link MenuAction}
+     * argument.
+     *
+     * @throws IllegalArgumentException if the path specified in
+     * {@link MenuAction#getPath()} can not be found
+     */
+    public void removeMenuAction(final MenuAction action) {
+        try {
+            new EdtHelper().callAndWait(new Runnable() {
+                @Override
+                public void run() {
+                    String[] path = action.getPath();
+                    Menu parent = findMenuParent(menuBar, path, false);
+                    parent.remove(path[path.length - 1]);
+                    menuBar.revalidate();
+                }
+            });
+        } catch (InterruptedException ie) {
+            Thread.currentThread().interrupt();
+            throw new RuntimeException(ie);
+        } catch (InvocationTargetException roe) {
+            Throwable cause = roe.getCause();
+            if (cause instanceof IllegalArgumentException) {
+                throw (IllegalArgumentException) cause;
+            }
+            throw new RuntimeException(cause);
+        }
+
+    }
+
+    private static Menu findMenuParent(JMenuBar menuBar, String[] path, boolean createIfNotFound) {
+        Menu parent = null;
+        int mainMenuCount = menuBar.getMenuCount();
+        for (int i = 0; i < mainMenuCount; i++) {
+            JMenu menu = menuBar.getMenu(i);
+            if (menu.getText().equals(path[0])) {
+                parent = new Menu(menuBar.getMenu(i));
+                break;
+            }
+        }
+        if (parent == null) {
+            if (createIfNotFound) {
+                JMenu delegate = new JMenu(path[0]);
+                parent = new Menu(delegate);
+                menuBar.add(delegate);
+            } else {
+                throw new IllegalArgumentException("top-level " + path[0] + " not found (using path" + Arrays.toString(path) + ")");
+            }
+        }
+
+        for (int i = 1; i < path.length - 1; i++) {
+            Menu[] children = parent.children();
+            boolean found = false;
+            for (int j = 0; j < children.length; j++) {
+                Menu menu = children[j];
+                if (menu.getText().equals(path[i])) {
+                    parent = menu;
+                    found = true;
+                }
+            }
+            if (!found) {
+                if (createIfNotFound) {
+                    Menu newMenu = new Menu(new JMenu(path[i]));
+                    parent.add(newMenu);
+                    parent = newMenu;
+                } else {
+                    throw new IllegalArgumentException("path not found");
+                }
+            }
+        }
+
+        return parent;
+    }
+
+    private static String getText(MenuElement element) {
+        if (element instanceof JMenuItem) {
+            return ((JMenuItem) element).getText();
+        }
+        return "";
+    }
+
+    @SuppressWarnings("unused") // this method is for debugging only
+    private static void printMenu(MenuElement parent, int nestingLevel) {
+        System.out.println(StringUtils.repeat(" ", nestingLevel * 2) + getText(parent) + " [" + parent.getClass() + "]");
+        for (MenuElement element : parent.getSubElements()) {
+            printMenu(element, nestingLevel + 1);
+        }
+    }
+
+    /**
+     * The swing menu hierarchy makes uniform operations very difficult. This
+     * is a hack around that.
+     */
+    private static final class Menu {
+        private Object swingDelegate;
+
+        public Menu() { /* no op */}
+
+        public Menu(JMenuItem actual) {
+            this.swingDelegate = actual;
+        }
+
+        public String getText() {
+            if (swingDelegate instanceof JMenuItem) {
+                return ((JMenuItem) swingDelegate).getText();
+            }
+            return null;
+        }
+
+        public Menu[] children() {
+            if (swingDelegate instanceof MenuElement) {
+                MenuElement[] actualChildren = ((MenuElement) swingDelegate).getSubElements();
+                if (actualChildren.length == 1 && actualChildren[0] instanceof JPopupMenu) {
+                    actualChildren = actualChildren[0].getSubElements();
+                }
+
+                Menu[] children = new Menu[actualChildren.length];
+                for (int i = 0; i < children.length; i++) {
+                    children[i] = new Menu((JMenuItem) actualChildren[i]);
+                }
+                return children;
+            }
+            return new Menu[0];
+        }
+
+        public void add(Menu menu) {
+            if (swingDelegate instanceof JPopupMenu) {
+                ((JPopupMenu) swingDelegate).add((JMenuItem) menu.swingDelegate);
+            } else if (swingDelegate instanceof JMenu) {
+                ((JMenu) swingDelegate).add((JMenuItem) menu.swingDelegate);
+            } else {
+                logger.warning("Unable to add menu. Menu is of unrecognized type: " + menu.swingDelegate);
+            }
+        }
+
+        public void remove(String string) {
+            JPopupMenu removeParent = null;
+
+            if (swingDelegate instanceof JMenu) {
+                JMenu parent = (JMenu) swingDelegate;
+                MenuElement[] actualChildren = parent.getSubElements();
+                if (actualChildren.length == 1 && actualChildren[0] instanceof JPopupMenu) {
+                    removeParent = (JPopupMenu) actualChildren[0];
+                }
+            }
+
+            if (removeParent == null) {
+                if (swingDelegate instanceof JPopupMenu) {
+                    removeParent = (JPopupMenu) swingDelegate;
+                } else {
+                    logger.warning("BUG: problem while removing menu. delegate is not a JPopupMenu, cant remove");
+                    return;
+                }
+            }
+
+            JPopupMenu parent = removeParent;
+            for (MenuElement element : parent.getSubElements()) {
+                if (((JMenuItem) element).getText().equals(string)) {
+                    parent.remove((JMenuItem) element);
+                }
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "Menu [" + swingDelegate.toString() + "]";
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/SwingComponent.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,10 @@
+package com.redhat.thermostat.client.swing;
+
+import java.awt.Component;
+
+import com.redhat.thermostat.client.core.views.UIComponent;
+
+public interface SwingComponent extends UIComponent {
+
+    Component getUiComponent();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/UIResources.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,115 @@
+/*
+ * 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.swing;
+
+import java.awt.Color;
+import java.awt.Font;
+
+import javax.swing.UIManager;
+import javax.swing.plaf.ColorUIResource;
+
+public class UIResources {
+
+    private static final UIResources resource = new UIResources();
+    
+    private static final ColorUIResource hyperLinkColor;
+    private static final ColorUIResource hyperLinkActiveColor;
+
+    private static final ColorUIResource selectionColor;
+    
+    private static final Font standard;
+    
+    static {
+        Color color = UIManager.getColor("Button.darkShadow");
+        if (color == null) {
+            color = Color.BLUE;
+        }
+        hyperLinkColor = new ColorUIResource(color);
+
+        color = UIManager.getColor("Button.focus");
+        if (color == null) {
+            color = Color.BLUE;
+        }
+        hyperLinkActiveColor = new ColorUIResource(color);
+        selectionColor = hyperLinkActiveColor;
+        
+        Font font = UIManager.getFont("Label.font");
+        if (font == null) {
+            font = Font.decode(Font.DIALOG);
+        }
+        standard = font;
+    }
+    
+    private static final Font header = standard.deriveFont(Font.BOLD);
+    
+    // TODO: check when size is too small
+    private static final Font footer = standard.deriveFont(Font.PLAIN, standard.getSize() - 2);
+    
+    private UIResources() { /* nothing to do */ }
+    
+    // colors
+
+    public static UIResources getInstance() {
+        return resource;
+    }
+    
+    public ColorUIResource hyperlinkColor() {
+        return hyperLinkColor;
+    }
+    
+    public ColorUIResource hyperlinkActiveColor() {
+        return hyperLinkActiveColor;
+    }
+    
+    public ColorUIResource getSelectionColor() {
+        return selectionColor;
+    }
+    
+    // font resources
+    
+    public Font footerFont() {
+        return footer;
+    }
+    
+    public Font headerFont() {
+        return header;
+    }
+    
+    public Font standardFont() {
+        return standard;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/ActionButton.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.components;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.lang.reflect.InvocationTargetException;
+
+import javax.swing.AbstractButton;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.SwingUtilities;
+
+@SuppressWarnings("serial")
+public class ActionButton extends JButton implements ToolbarButton {
+    
+    private String lastText;
+    private boolean showText;
+    
+    public ActionButton(final Icon icon) {
+        this(icon, "");
+    }
+    
+    public ActionButton(final Icon icon, String text) {
+        super(icon);
+                
+        showText = true;
+        setText(text);
+        
+        setUI(new ActionButtonUI());
+        setOpaque(false);
+        setContentAreaFilled(false);
+        setBorder(new ToolbarButtonBorder(this));
+    }
+        
+    @Override
+    public AbstractButton getToolbarButton() {
+        return this;
+    }
+    
+    @Override
+    public void setText(String text) {
+        lastText = text;
+        if (showText) {
+            super.setText(text);
+        }
+    }
+    
+    private void setText_noClient(String text) {
+        super.setText(text);
+    }
+    
+    @Override
+    public void toggleText(boolean showText) {
+        this.showText = showText;
+        if (showText) {
+            setText_noClient(lastText);
+        } else {
+            setText_noClient("");
+        }
+    }
+    
+    public static void main(String[] args) throws InvocationTargetException, InterruptedException {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            
+            @Override
+            public void run() {
+               JFrame frame = new JFrame();
+               frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+               
+               HeaderPanel header = new HeaderPanel();
+               header.setHeader("Test");
+               
+               Icon icon = new Icon() {
+                
+                @Override
+                public void paintIcon(Component c, Graphics g, int x, int y) {
+                    g.setColor(Color.CYAN);
+                    g.fillRect(x, y, 16, 16);
+
+                }
+                
+                @Override
+                public int getIconWidth() {
+                    // TODO Auto-generated method stub
+                    return 16;
+                }
+                
+                @Override
+                public int getIconHeight() {
+                    // TODO Auto-generated method stub
+                    return 16;
+                }
+            }; 
+               
+               header.addToolBarButton(new ActionButton(icon, "Fluff"));
+               
+               frame.getContentPane().add(header);
+               frame.setSize(500, 500);
+               frame.setVisible(true);
+            }
+        });
+    }      
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/ActionButtonUI.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,145 @@
+/*
+ * 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.swing.components;
+
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ConvolveOp;
+import java.awt.image.Kernel;
+
+import javax.swing.AbstractButton;
+import javax.swing.ButtonModel;
+import javax.swing.Icon;
+import javax.swing.JComponent;
+import javax.swing.plaf.metal.MetalButtonUI;
+
+import com.redhat.thermostat.client.ui.Palette;
+
+class ActionButtonUI extends MetalButtonUI {
+
+    private BufferedImage sourceIcon;
+    private BufferedImage rollOverIcon;
+    
+    ActionButtonUI() {}
+    
+    private BufferedImage getBrighterImage(BufferedImage source) {
+        float[] kernel = new float[] { 0, 0, 0, 0, 1.2f, 0, 0, 0, 0 };
+
+        BufferedImageOp brighterOp = new ConvolveOp(new Kernel(3, 3, kernel),
+                ConvolveOp.EDGE_NO_OP, null);
+        return brighterOp.filter(source, new BufferedImage(source.getWidth(),
+                source.getHeight(), source.getType()));
+    }
+    
+    @Override
+    protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect,
+                              Rectangle textRect, Rectangle iconRect)
+    {
+        // nothing to do
+    }
+    
+    @Override
+    protected void paintIcon(Graphics g, JComponent c, Rectangle iconRect) {
+        
+        AbstractButton button = (AbstractButton) c;
+        ButtonModel model = button.getModel();
+        
+        Icon icon = button.getIcon();
+        int w = icon.getIconWidth();
+        int h = icon.getIconHeight();
+
+        if (sourceIcon == null) {
+            sourceIcon = new BufferedImage(w + 1, h + 1,
+                    BufferedImage.TYPE_INT_ARGB);
+            Graphics imageGraphics = sourceIcon.getGraphics();
+            icon.paintIcon(null, imageGraphics, 0, 0);
+        }
+
+        if (rollOverIcon == null) {
+            rollOverIcon = getBrighterImage(sourceIcon);
+        }
+        
+        int x = 3;
+        int y = button.getHeight() / 2 - h / 2;
+
+        String text = button.getText();
+        if (text == null || text.equals("")) {
+            x = button.getWidth() / 2 - w / 2;
+        }
+        
+        if (model.isRollover()) {
+            g.drawImage(rollOverIcon, x, y, null);
+        } else {
+            g.drawImage(sourceIcon, x, y, null);
+        }
+    }
+    
+    @Override
+    protected void paintText(Graphics g, AbstractButton b, Rectangle textRect, String text) {
+        GraphicsUtils graphicsUtils = GraphicsUtils.getInstance();
+        Graphics2D graphics = graphicsUtils.createAAGraphics(g);
+        FontMetrics metrics = b.getFontMetrics(b.getFont());
+        graphicsUtils.drawStringWithShadow(b, graphics, text, b.getForeground(), textRect.x,
+                                           textRect.y + metrics.getAscent());
+    }
+
+    @Override
+    public void paint(Graphics g, JComponent c) {
+
+        AbstractButton button = (AbstractButton) c;
+        ButtonModel model = button.getModel();
+
+        if (model.isRollover() || model.isPressed() || model.isSelected()) {
+            GraphicsUtils graphicsUtils = GraphicsUtils.getInstance();
+            Graphics2D graphics = graphicsUtils.createAAGraphics(g);
+
+            graphicsUtils.setGradientPaint(graphics, 0, button.getHeight(), button.getBackground(), Palette.WHITE.getColor());
+            
+            Shape shape = graphicsUtils.getRoundShape(button.getWidth() - 1, button.getHeight() - 1);
+            graphics.fill(shape);
+            
+            graphics.dispose();
+        }
+        
+        super.paint(g, c);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/ActionToggleButton.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,138 @@
+/*
+ * 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.swing.components;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.lang.reflect.InvocationTargetException;
+
+import javax.swing.AbstractButton;
+import javax.swing.Icon;
+import javax.swing.JFrame;
+import javax.swing.JToggleButton;
+import javax.swing.SwingUtilities;
+
+@SuppressWarnings("serial")
+public class ActionToggleButton extends JToggleButton implements ToolbarButton {
+        
+    private String lastText;
+    private boolean showText;
+    public ActionToggleButton(final Icon icon) {
+        this(icon, "");
+    }
+    
+    public ActionToggleButton(final Icon icon, String text) {
+        super(icon);
+                
+        showText = true;
+        setText(text);
+        
+        setUI(new ActionButtonUI());
+        setOpaque(false);
+        setContentAreaFilled(false);
+        setBorder(new ToolbarButtonBorder(this));
+    }
+    
+    @Override
+    public AbstractButton getToolbarButton() {
+        return this;
+    }
+    
+    @Override
+    public void setText(String text) {
+        lastText = text;
+        if (showText) {
+            super.setText(text);
+        }
+    }
+    
+    private void setText_noClient(String text) {
+        super.setText(text);
+    }
+    
+    @Override
+    public void toggleText(boolean showText) {
+        this.showText = showText;
+        if (showText) {
+            setText_noClient(lastText);
+        } else {
+            setText_noClient("");
+        }
+    }
+    
+    public static void main(String[] args) throws InvocationTargetException, InterruptedException {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            
+            @Override
+            public void run() {
+               JFrame frame = new JFrame();
+               frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+               
+               HeaderPanel header = new HeaderPanel();
+               header.setHeader("Test");
+               
+               Icon icon = new Icon() {
+                   @Override
+                   public void paintIcon(Component c, Graphics g, int x, int y) {
+                       g.setColor(Color.CYAN);
+                       g.fillRect(x, y, 16, 16);
+                   }
+                
+                   @Override
+                   public int getIconWidth() {
+                       return 16;
+                   }
+                
+                   @Override
+                   public int getIconHeight() {
+                       return 16;
+                   }
+               }; 
+               
+               ActionToggleButton button = new ActionToggleButton(icon);
+               header.addToolBarButton(button);
+               
+               button.setText("fluff");
+               
+               frame.getContentPane().add(header);
+               frame.setSize(500, 500);
+               frame.setVisible(true);
+            }
+        });
+    }     
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/ChartPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.components;
+
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+
+import javax.swing.JPanel;
+
+import org.jfree.chart.ChartRenderingInfo;
+import org.jfree.chart.JFreeChart;
+
+@SuppressWarnings("serial")
+public class ChartPanel extends JPanel {
+
+    private JFreeChart chart;
+    private ChartRenderingInfo info;
+    
+    public ChartPanel(JFreeChart chart) {
+        this(chart, new ChartRenderingInfo());
+    }
+    
+    public ChartPanel(JFreeChart chart, ChartRenderingInfo info) {
+        this.chart = chart;
+        this.info = info;
+    }
+    
+    @Override
+    protected void paintComponent(Graphics g) {
+        BufferedImage image = chart.createBufferedImage(getWidth(), getHeight(), info);
+        g.drawImage(image, 0, 0, null);
+    }
+    
+    public ChartRenderingInfo getChartRenderingInfo() {
+        return info;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/Components.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,60 @@
+/*
+ * 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.swing.components;
+
+import javax.swing.BorderFactory;
+import javax.swing.JLabel;
+import javax.swing.SwingConstants;
+import javax.swing.border.Border;
+
+public class Components {
+    public static JLabel header(String text) {
+        JLabel label = new JLabel(HtmlTextBuilder.boldHtml(text));
+        label.setHorizontalAlignment(SwingConstants.LEADING);
+        return label;
+    }
+
+    public static JLabel label(String string) {
+        JLabel label = new JLabel(string);
+        label.setHorizontalAlignment(SwingConstants.TRAILING);
+        return label;
+    }
+
+    public static Border smallBorder() {
+        return BorderFactory.createEmptyBorder(5, 5, 5, 5);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/DebugBorder.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,89 @@
+/*
+ * 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.swing.components;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Insets;
+import java.awt.Shape;
+import java.awt.geom.RoundRectangle2D;
+import java.io.Serializable;
+
+import javax.swing.border.AbstractBorder;
+import javax.swing.plaf.UIResource;
+
+@SuppressWarnings("serial")
+public class DebugBorder extends AbstractBorder implements UIResource, Serializable {
+
+    @Override
+    public void paintBorder(Component c, Graphics g, int x, int y, int width,
+                            int height)
+    {
+        Graphics2D graphics = (Graphics2D) g.create();
+
+        graphics.translate(x, y);
+        
+        graphics.setPaint(Color.RED);
+        
+        float dash[] = { 10.0f };
+        graphics.setStroke(new BasicStroke(3.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f));
+        
+        Shape shape = new RoundRectangle2D.Float(0, 0, width - 1,
+                                                 height - 1, 4, 4);
+        graphics.draw(shape);
+        graphics.dispose();
+    }
+    
+    @Override
+    public Insets getBorderInsets(Component c) {
+        return getBorderInsets(c, new Insets(0, 0, 0, 0));
+    }
+
+    @Override
+    public Insets getBorderInsets(Component c, Insets insets) {
+        
+        insets.top = 4;
+        insets.left = 4;
+        insets.right = 4;
+        insets.bottom = 4;
+        
+        return insets;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/EdtHelper.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,95 @@
+/*
+ * 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.swing.components;
+
+import java.awt.EventQueue;
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.Callable;
+
+public class EdtHelper {
+
+    @SuppressWarnings("serial")
+    private static class CallableException extends RuntimeException {
+
+        private CallableException(Exception ex) {
+            super(ex);
+        }
+        
+    }
+
+    private static class CallableWrapper<T> implements Runnable {
+
+        private Callable<T> callable;
+        private T result;
+
+        private CallableWrapper(Callable<T> c) {
+            callable = c;
+        }
+
+        @Override
+        public void run() {
+            try {
+                result = callable.call();
+            } catch (Exception ex) {
+                throw new CallableException(ex);
+            }
+        }
+
+        private T getResult() {
+            return result;
+        }
+    }
+
+    public void callAndWait(Runnable r) throws InvocationTargetException, InterruptedException {
+        if (EventQueue.isDispatchThread()) {
+            try {
+                r.run();
+            } catch (Exception ex) {
+                throw new InvocationTargetException(ex);
+            }
+        } else {
+            EventQueue.invokeAndWait(r);
+        }
+    }
+
+    public <T> T callAndWait(Callable<T> c) throws InvocationTargetException, InterruptedException {
+        CallableWrapper<T> w = new CallableWrapper<>(c);
+        callAndWait(w);
+        return w.getResult();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/EmptyIcon.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.components;
+
+import java.awt.Component;
+import java.awt.Graphics;
+
+import javax.swing.ImageIcon;
+
+@SuppressWarnings("serial")
+public class EmptyIcon extends ImageIcon  {
+
+    private int width;
+    private int height;
+    
+    public EmptyIcon() {
+        this(16, 16);
+    }
+    
+    public EmptyIcon(int width, int height) {
+        this.width = width;
+        this.height = height;
+    }
+    
+    @Override
+    public int getIconHeight() {
+        return height;
+    }
+    
+    @Override
+    public int getIconWidth() {
+        return width;
+    }
+    
+    @Override
+    public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
+        // no-op
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/GradientPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.swing.components;
+
+import java.awt.Color;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+
+import javax.swing.JPanel;
+
+
+@SuppressWarnings("serial")
+public class GradientPanel extends JPanel {
+
+    private Color top;
+    private Color bottom;
+    
+    public GradientPanel(Color top, Color bottom) {
+        this.top = top;
+        this.bottom = bottom;
+    }
+    
+    @Override
+    protected void paintComponent(Graphics g) {
+        
+        Graphics2D graphics = GraphicsUtils.getInstance().createAAGraphics(g);
+        
+        Paint gradient = new GradientPaint(0, 0, top, 0, getHeight(), bottom);
+        graphics.setPaint(gradient);
+        graphics.fillRect(0, 0, getWidth(), getHeight());
+        graphics.dispose();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/GradientRoundBorder.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,76 @@
+/*
+ * 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.swing.components;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Shape;
+import java.io.Serializable;
+
+import javax.swing.UIManager;
+import javax.swing.border.AbstractBorder;
+import javax.swing.plaf.UIResource;
+
+import com.redhat.thermostat.client.ui.Palette;
+
+@SuppressWarnings("serial")
+public class GradientRoundBorder extends AbstractBorder implements UIResource, Serializable {
+
+    @Override
+    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
+        GraphicsUtils utils = GraphicsUtils.getInstance();
+        Graphics2D graphics = utils.createAAGraphics(g);
+        
+        Color highlight = UIManager.getColor("textHighlight");
+        if (highlight == null) {
+            highlight = Palette.EGYPTIAN_BLUE.getColor();
+        }
+        Paint paint = new GradientPaint(x, y, highlight, 0, height, c.getBackground());
+        graphics.setPaint(paint);
+        
+        graphics.translate(x, y);
+        
+        Shape shape = utils.getRoundShape(width, height);
+        graphics.draw(shape);
+        
+        graphics.dispose();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/GraphicsUtils.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,95 @@
+/*
+ * 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.swing.components;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.geom.RoundRectangle2D;
+
+import javax.swing.JComponent;
+
+import sun.swing.SwingUtilities2;
+
+@SuppressWarnings("restriction")
+public class GraphicsUtils {
+
+    private static GraphicsUtils instance = new GraphicsUtils();
+    public static GraphicsUtils getInstance() {
+        return instance;
+    }
+    
+    public Graphics2D createAAGraphics(Graphics g) {
+        Graphics2D graphics = (Graphics2D) g.create();
+        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        return graphics;
+    }
+    
+    public void drawStringWithShadow(JComponent component, Graphics2D graphics, String string, Color foreground, int x, int y) {
+        // paint it twice to give a subtle drop shadow effect
+        
+        graphics.setColor(new Color(0f, 0f, 0f, 0.1f));
+        SwingUtilities2.drawString(component, graphics, string, x, y + 1);
+        
+        graphics.setColor(foreground);
+        SwingUtilities2.drawString(component, graphics, string, x, y);
+    }
+    
+    public void drawString(JComponent component, Graphics2D graphics, String string, Color foreground, int x, int y) {
+        graphics.setColor(foreground);
+        SwingUtilities2.drawString(component, graphics, string, x, y);
+    }
+    
+    public FontMetrics getFontMetrics(JComponent component, Font font) {
+        return SwingUtilities2.getFontMetrics(component, font);
+    }
+    
+    public Shape getRoundShape(int width, int height) {
+        return new RoundRectangle2D.Double(0, 0, width, height, 4, 4);
+    }
+    
+    public void setGradientPaint(Graphics2D g, int x, int height, Color start, Color stop) {
+        Paint paint = new GradientPaint(x, 0, start, 0, height, stop);
+        g.setPaint(paint);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/HeaderPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,238 @@
+/*
+ * 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.swing.components;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.lang.reflect.InvocationTargetException;
+import java.util.prefs.PreferenceChangeEvent;
+import java.util.prefs.PreferenceChangeListener;
+import java.util.prefs.Preferences;
+
+import javax.swing.AbstractButton;
+import javax.swing.BoxLayout;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
+
+/**
+ * A component that host a panel with a nicely rendered header.
+ */
+@SuppressWarnings("serial")
+public class HeaderPanel extends JPanel {
+        
+    public static final String SHOW_TEXT = "SHOW_TEXT";
+    
+    private boolean showText;
+    
+    private String header;
+    
+    private JPanel contentPanel;
+    private JLabel headerLabel;
+    private JPanel headerPanel;
+    private JPanel controlPanel;
+    
+    private boolean hasButtons;
+    
+    private Preferences prefs;
+    
+    public HeaderPanel() {
+        this("");
+    }
+    
+    public HeaderPanel(String header) {
+        this(Preferences.userRoot().node(HeaderPanel.class.getName()), "");
+    }
+    
+    public HeaderPanel(Preferences prefs, String header) {
+                
+        this.prefs = prefs;
+        
+        this.header = header;
+        
+        setLayout(new BorderLayout(0, 0));
+
+        headerLabel = new ShadowLabel(header, new EmptyIcon(5, 5));
+        headerPanel = new GradientPanel(Color.WHITE, getBackground());
+        headerPanel.setName("clickableArea");
+        headerPanel.setPreferredSize(new Dimension(HeaderPanel.this.getWidth(), 40));
+        
+        headerPanel.setLayout(new BorderLayout(0, 0));
+        headerPanel.add(headerLabel, BorderLayout.WEST);
+        add(headerPanel, BorderLayout.NORTH);
+        
+        controlPanel = new JPanel();
+        controlPanel.setOpaque(false);
+        controlPanel.setLayout(new FlowLayout(FlowLayout.RIGHT, 2, 10));
+        
+        headerPanel.add(controlPanel, BorderLayout.EAST);
+        
+        contentPanel = new JPanel();
+        contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.X_AXIS));
+        
+        add(contentPanel, BorderLayout.CENTER);
+        showText = prefs.getBoolean(HeaderPanel.class.getName(), false);
+        registerPreferences();
+        
+        headerPanel.addMouseListener(new PreferencesPopupListener());
+    }
+   
+    public boolean isShowToolbarText() {
+        return showText;
+    }
+    
+    private void registerPreferences() {
+        prefs.addPreferenceChangeListener(new PreferenceChangeListener() {
+            @Override
+            public void preferenceChange(PreferenceChangeEvent evt) {
+                
+                String key = evt.getKey();
+                boolean _value = false;
+                if (key.equalsIgnoreCase(HeaderPanel.class.getName())) {
+                    _value = prefs.getBoolean(HeaderPanel.class.getName(), false);
+                }
+                final boolean value = _value;
+                SwingUtilities.invokeLater(new Runnable() {
+                    @Override
+                    public void run() {
+                        boolean oldShowText = showText;
+                        showText = value;
+                        firePropertyChange(SHOW_TEXT, oldShowText, showText);
+                    }
+                });
+            }
+        });
+    }
+    
+    public String getHeader() {
+        return header;
+    }
+    
+    public void setHeader(String header) {
+        this.header = header;
+        headerLabel.setText(header);
+    }
+    
+    public void setContent(JComponent content) {
+        contentPanel.removeAll();
+        contentPanel.add(content);
+        contentPanel.revalidate();
+        repaint();
+    }
+    
+    public void addToolBarButton(final ToolbarButton button) {
+        AbstractButton theButton = button.getToolbarButton();
+        button.toggleText(isShowToolbarText());
+        addPropertyChangeListener(SHOW_TEXT, new PropertyChangeListener() {
+            @Override
+            public void propertyChange(PropertyChangeEvent evt) {
+                button.toggleText(isShowToolbarText());
+            }
+        });
+        controlPanel.add(theButton);
+        hasButtons = true;
+    }
+    
+    class PreferencesPopup extends JPopupMenu {
+        JMenuItem preferencesMenu;
+        public PreferencesPopup() {
+            // TODO: localize
+            String text = "Show button text";
+            if (showText) {
+                text = "Hide button text";
+            }
+            preferencesMenu = new JMenuItem(text);
+            preferencesMenu.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    prefs.putBoolean(HeaderPanel.class.getName(), !showText);
+                }
+            });
+            add(preferencesMenu);
+        }
+    }
+
+    class PreferencesPopupListener extends MouseAdapter {
+        public void mousePressed(MouseEvent e){
+            if (e.isPopupTrigger()) {
+                popupPreferences(e);
+            }
+        }
+
+        public void mouseReleased(MouseEvent e){
+            if (e.isPopupTrigger()) {
+                popupPreferences(e);
+            }
+        }
+
+        private void popupPreferences(MouseEvent e){
+            if (hasButtons) {
+                PreferencesPopup menu = new PreferencesPopup();
+                menu.show(e.getComponent(), e.getX(), e.getY());
+            }
+        }
+    }
+    
+    public static void main(String[] args) throws InvocationTargetException, InterruptedException {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            
+            @Override
+            public void run() {
+               JFrame frame = new JFrame();
+               frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+               
+               HeaderPanel header = new HeaderPanel();
+               header.setHeader("Test");
+               frame.getContentPane().add(header);
+               frame.setSize(500, 500);
+               frame.setVisible(true);
+            }
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/HtmlTextBuilder.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,118 @@
+/*
+ * 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.swing.components;
+
+public class HtmlTextBuilder {
+
+    /*
+     * The api provided by this class needs to be cleaned up.
+     */
+
+    private final StringBuilder text = new StringBuilder();
+
+    public HtmlTextBuilder() {
+        // do nothing
+    }
+
+    public HtmlTextBuilder(String text) {
+        text = escape(text);
+        this.text.append(text);
+    }
+
+    public HtmlTextBuilder bold(boolean on) {
+        if (on) {
+            this.text.append("<b>");
+        } else {
+            this.text.append("</b>");
+        }
+        return this;
+    }
+
+    public HtmlTextBuilder bold(String toBold) {
+        text.append("<b>").append(toBold).append("</b>");
+        return this;
+    }
+
+    public HtmlTextBuilder larger(String toAppend) {
+        text.append("<font size='+2'>").append(escape(toAppend)).append("</font>");
+        return this;
+    }
+
+    public HtmlTextBuilder huge(String toAppend) {
+        text.append("<font size='+6'>").append(escape(toAppend)).append("</font>");
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        // FIXME
+        return null;
+    }
+
+    public String toHtml() {
+        return "<html>" + text.toString() + "</html>";
+    }
+
+    public String toPartialHtml() {
+        return text.toString();
+    }
+
+    private static String escape(String toEscape) {
+        // FIXME implement this
+        return toEscape;
+    }
+
+    public HtmlTextBuilder append(String toAppend) {
+        text.append(escape(toAppend));
+        return this;
+    }
+
+    public HtmlTextBuilder appendRaw(String toAppend) {
+        text.append(toAppend);
+        return this;
+    }
+
+    public static String boldHtml(String toBold) {
+        return new HtmlTextBuilder().bold(toBold).toHtml();
+    }
+
+    public HtmlTextBuilder newLine() {
+        text.append("<br>");
+        return this;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/LabelField.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.components;
+
+import javax.swing.JLabel;
+import javax.swing.SwingConstants;
+
+@SuppressWarnings("serial")
+public class LabelField extends JLabel {
+
+    public LabelField(String text) {
+        super(text);
+        setHorizontalAlignment(SwingConstants.TRAILING);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/RecentTimeSeriesChartPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,220 @@
+/*
+ * 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.swing.components;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.concurrent.TimeUnit;
+
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.JTextComponent;
+
+import org.jfree.chart.ChartPanel;
+
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.ui.RecentTimeSeriesChartController;
+import com.redhat.thermostat.common.locale.Translate;
+
+public class RecentTimeSeriesChartPanel extends JPanel {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private static final long serialVersionUID = -1733906800911900456L;
+    private static final int MINIMUM_DRAW_SIZE = 100;
+
+    private final RecentTimeSeriesChartController controller;
+
+    private JPanel labelContainer;
+    private JTextComponent label;
+
+    public RecentTimeSeriesChartPanel(RecentTimeSeriesChartController controller) {
+        this.controller = controller;
+
+        this.setLayout(new BorderLayout());
+
+        final ChartPanel cp = controller.getChartPanel();
+
+        cp.setDisplayToolTips(false);
+        cp.setDoubleBuffered(true);
+        cp.setMouseZoomable(false);
+        cp.setPopupMenu(null);
+
+        /*
+         * 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.
+         */
+        cp.setMinimumDrawHeight(MINIMUM_DRAW_SIZE);
+        cp.setMaximumDrawHeight(Integer.MAX_VALUE);
+        cp.setMinimumDrawWidth(MINIMUM_DRAW_SIZE);
+        cp.setMaximumDrawWidth(Integer.MAX_VALUE);
+
+        add(getControlsAndAdditionalDisplay(), BorderLayout.SOUTH);
+
+        add(cp, BorderLayout.CENTER);
+    }
+
+    private Component getControlsAndAdditionalDisplay() {
+        JPanel container = new JPanel();
+        container.setOpaque(false);
+
+        container.setLayout(new BorderLayout());
+
+        container.add(getChartControls(), BorderLayout.LINE_START);
+        container.add(getAdditionalDataDisplay(), BorderLayout.LINE_END);
+
+        return container;
+    }
+
+    private Component getChartControls() {
+        JPanel container = new JPanel();
+        container.setOpaque(false);
+
+        final JTextField durationSelector = new JTextField(5);
+        final JComboBox<TimeUnit> unitSelector = new JComboBox<>();
+        unitSelector.setModel(new DefaultComboBoxModel<>(controller.getTimeUnits()));
+
+        int defaultValue = controller.getTimeValue();
+        TimeUnit defaultUnit = controller.getTimeUnit();
+
+        TimeUnitChangeListener timeUnitChangeListener = new TimeUnitChangeListener(controller, defaultValue, defaultUnit);
+
+        durationSelector.getDocument().addDocumentListener(timeUnitChangeListener);
+        unitSelector.addActionListener(timeUnitChangeListener);
+
+        durationSelector.setText(String.valueOf(defaultValue));
+        unitSelector.setSelectedItem(defaultUnit);
+
+        container.add(new JLabel(translator.localize(LocaleResources.CHART_DURATION_SELECTOR_LABEL)));
+        container.add(durationSelector);
+        container.add(unitSelector);
+
+        return container;
+    }
+
+    private Component getAdditionalDataDisplay() {
+        JPanel panel = new JPanel(new GridBagLayout());
+        panel.setOpaque(false);
+        labelContainer = new JPanel();
+        labelContainer.setOpaque(false);
+        GridBagConstraints constraints = new GridBagConstraints();
+        constraints.fill = GridBagConstraints.BOTH;
+        constraints.anchor = GridBagConstraints.CENTER;
+        panel.add(labelContainer, constraints);
+        return panel;
+    }
+
+    public void setDataInformationLabel(final String text) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                if (label == null) {
+                    label = new ValueField(text);
+                    labelContainer.add(label);
+                }
+
+                label.setText(text);
+            }
+        });
+    }
+
+    private static class TimeUnitChangeListener implements DocumentListener, ActionListener {
+
+        private final RecentTimeSeriesChartController controller;
+        private int value;
+        private TimeUnit unit;
+
+        public TimeUnitChangeListener(RecentTimeSeriesChartController controller, int defaultValue, TimeUnit defaultUnit) {
+            this.controller = controller;
+            this.value = defaultValue;
+            this.unit = defaultUnit;
+        }
+
+        @Override
+        public void removeUpdate(DocumentEvent event) {
+            changed(event.getDocument());
+        }
+
+        @Override
+        public void insertUpdate(DocumentEvent event) {
+            changed(event.getDocument());
+        }
+
+        @Override
+        public void changedUpdate(DocumentEvent event) {
+            changed(event.getDocument());
+        }
+
+        private void changed(Document doc) {
+            try {
+                this.value = Integer.valueOf(doc.getText(0, doc.getLength()));
+            } catch (NumberFormatException nfe) {
+                // ignore
+            } catch (BadLocationException ble) {
+                // ignore
+            }
+            updateChartParameters();
+        }
+
+        private void updateChartParameters() {
+            controller.setTime(value, unit);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            @SuppressWarnings("unchecked") // We are a TimeUnitChangeListener, specifically.
+            JComboBox<TimeUnit> comboBox = (JComboBox<TimeUnit>) e.getSource();
+            TimeUnit time = (TimeUnit) comboBox.getSelectedItem();
+            this.unit = time;
+            updateChartParameters();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/SectionHeader.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.components;
+
+import javax.swing.JLabel;
+import javax.swing.SwingConstants;
+
+@SuppressWarnings("serial")
+public class SectionHeader extends JLabel {
+
+    public SectionHeader(String text) {
+        super(HtmlTextBuilder.boldHtml(text));
+        setHorizontalAlignment(SwingConstants.LEADING);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/ShadowLabel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,68 @@
+/*
+ * 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.swing.components;
+
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+
+import javax.swing.Icon;
+import javax.swing.JLabel;
+import javax.swing.plaf.metal.MetalLabelUI;
+
+@SuppressWarnings("serial")
+public class ShadowLabel extends JLabel {
+
+    public ShadowLabel(String text, Icon icon) {
+        super(text);
+        this.setIcon(icon);
+        setUI(new ShadowLabelUI());
+    }
+    
+    public ShadowLabel(String text) {
+        this(text, null);
+    }
+
+    private class ShadowLabelUI extends MetalLabelUI {
+        
+        @Override
+        protected void paintEnabledText(JLabel l, Graphics g, String s, int textX, int textY) {
+            GraphicsUtils graphicsUtils = GraphicsUtils.getInstance();
+            Graphics2D graphics = graphicsUtils.createAAGraphics(g);
+            graphicsUtils.drawStringWithShadow(l, graphics, s, getForeground(), textX, textY);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/SimpleTable.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,290 @@
+/*
+ * 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.swing.components;
+
+import java.awt.Component;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import javax.swing.Box;
+import javax.swing.JComponent;
+import javax.swing.JEditorPane;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+
+import com.redhat.thermostat.client.swing.internal.ChangeableText;
+import com.redhat.thermostat.client.ui.ComponentVisibleListener;
+
+public class SimpleTable implements ChangeableText.TextListener {
+
+    Map<ChangeableText, Set<JComponent>> updateMap = new HashMap<ChangeableText, Set<JComponent>>();
+
+    public static class Section {
+        private final String sectionName;
+        private final List<TableEntry> tableEntries = new ArrayList<TableEntry>();
+
+        public Section(String name) {
+            this.sectionName = name;
+        }
+
+        public String getText() {
+            return sectionName;
+        }
+
+        public void add(TableEntry entry) {
+            tableEntries.add(entry);
+        }
+
+        public void add(Key key, List<Value> values) {
+            tableEntries.add(new TableEntry(key, values));
+        }
+
+        public void add(Key key, Value value) {
+            tableEntries.add(new TableEntry(key, value));
+        }
+
+        public TableEntry[] getEntries() {
+            return tableEntries.toArray(new TableEntry[0]);
+        }
+    }
+
+    public static class TableEntry {
+        private final Key key;
+        private final List<Value> values;
+
+        public TableEntry(String key, ChangeableText value) {
+            this(new Key(key), new Value(value));
+        }
+
+        public TableEntry(Key key, Value value) {
+            this.key = key;
+            this.values = new ArrayList<Value>();
+            this.values.add(value);
+        }
+
+        public TableEntry(Key key, List<Value> values) {
+            this.key = key;
+            this.values = new ArrayList<Value>(values);
+        }
+
+        public Key getKey() {
+            return key;
+        }
+
+        public Value[] getValues() {
+            return values.toArray(new Value[0]);
+        }
+    }
+
+    public static class Key {
+        private final String text;
+
+        public Key(String text) {
+            this.text = text;
+        }
+
+        public String getText() {
+            return text;
+        }
+    }
+
+    public static class Value {
+        private final ChangeableText text;
+        private final Component actualComponent;
+
+        public Value(String text) {
+            this(new ChangeableText(text));
+        }
+
+        public Value(ChangeableText text) {
+            this.text = text;
+            this.actualComponent = null;
+        }
+
+        public Value(Component component) {
+            this.actualComponent = component;
+            this.text = null;
+        }
+
+        public Component getComponent() {
+            return actualComponent;
+        }
+
+        public ChangeableText getChangeableText() {
+            return text;
+        }
+    }
+
+    public JPanel createTable(List<Section> sections) {
+        final int SECTION_TOP_GAP = 10;
+        final int ROW_VERTICAL_GAP = 0;
+        final int ROW_HORIZONTAL_GAP = 10;
+
+        Insets sectionHeaderInsets = new Insets(SECTION_TOP_GAP, 0, 0, 0);
+        Insets rowInsets = new Insets(ROW_VERTICAL_GAP, ROW_HORIZONTAL_GAP, ROW_VERTICAL_GAP, ROW_HORIZONTAL_GAP);
+
+        JPanel container = new JPanel();
+        container.setLayout(new GridBagLayout());
+
+        GridBagConstraints keyConstraints = new GridBagConstraints();
+        GridBagConstraints valueConstraints = new GridBagConstraints();
+        GridBagConstraints sectionHeaderConstraints = new GridBagConstraints();
+
+        keyConstraints.insets = valueConstraints.insets = rowInsets;
+        keyConstraints.gridy = valueConstraints.gridy = 0;
+        keyConstraints.gridx = 0;
+        keyConstraints.anchor = GridBagConstraints.FIRST_LINE_END;
+        valueConstraints.gridx = 1;
+        keyConstraints.fill = valueConstraints.fill = GridBagConstraints.HORIZONTAL;
+
+        sectionHeaderConstraints.gridx = 0;
+        sectionHeaderConstraints.gridwidth = GridBagConstraints.REMAINDER;
+        sectionHeaderConstraints.fill = GridBagConstraints.HORIZONTAL;
+        sectionHeaderConstraints.insets = sectionHeaderInsets;
+
+        for (Section section : sections) {
+            sectionHeaderConstraints.gridy = keyConstraints.gridy = ++valueConstraints.gridy;
+            container.add(Components.header(section.getText()), sectionHeaderConstraints);
+            for (TableEntry tableEntry : section.getEntries()) {
+                keyConstraints.gridy = ++valueConstraints.gridy;
+                container.add(Components.label(tableEntry.getKey().getText()), keyConstraints);
+
+                for (Value value : tableEntry.getValues()) {
+                    if (value.getComponent() == null) {
+                        ChangeableText text = value.getChangeableText();
+                        JComponent valueLabel = new ValueField(text.getText());
+                        if (updateMap.containsKey(text)) {
+                            updateMap.get(text).add(valueLabel);
+                        } else {
+                            Set<JComponent> set = new HashSet<JComponent>();
+                            set.add(valueLabel);
+                            updateMap.put(text, set);
+                        }
+                        container.add(valueLabel, valueConstraints);
+                    } else {
+                        container.add(value.getComponent(), valueConstraints);
+                    }
+                    keyConstraints.gridy = ++valueConstraints.gridy;
+                }
+            }
+        }
+
+        GridBagConstraints glueConstraints = new GridBagConstraints();
+        glueConstraints.gridy = keyConstraints.gridy + 1;
+        glueConstraints.gridx = 0;
+        glueConstraints.weightx = 1;
+        glueConstraints.weighty = 1;
+        glueConstraints.fill = GridBagConstraints.BOTH;
+        glueConstraints.gridheight = GridBagConstraints.REMAINDER;
+        glueConstraints.gridwidth = GridBagConstraints.REMAINDER;
+        Component filler = Box.createGlue();
+        container.add(filler, glueConstraints);
+
+        container.addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component c) {
+                updateAllValues();
+                addAllListeners();
+            }
+
+            @Override
+            public void componentHidden(Component c) {
+                removeAllListeners();
+            }
+        });
+
+        return container;
+    }
+
+
+    private void updateAllValues() {
+        for (Entry<ChangeableText, Set<JComponent>> entry: updateMap.entrySet()) {
+            for (JComponent label: entry.getValue()) {
+                setText(label, entry.getKey().getText());
+            }
+        }
+    }
+
+    private static void setText(JComponent target, String text) {
+        if (target instanceof JLabel) {
+            ((JLabel)target).setText(text);
+        } else if (target instanceof JTextField) {
+            ((JTextField)target).setText(text);
+        } else if (target instanceof JTextArea) {
+            ((JTextArea)target).setText(text);
+        } else if (target instanceof JEditorPane) {
+            ((JEditorPane)target).setText(text);
+        }
+    }
+
+    @Override
+    public void textChanged(final ChangeableText text) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                String newValue = text.getText();
+                for (JComponent label: updateMap.get(text)) {
+                    setText(label, newValue);
+                }
+            }
+        });
+    }
+
+    public void addAllListeners() {
+        for (ChangeableText text : updateMap.keySet()) {
+            text.addListener(this);
+        }
+    }
+
+    public void removeAllListeners() {
+        for (ChangeableText text : updateMap.keySet()) {
+            text.removeListener(this);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/StatusBar.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.components;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.beans.Transient;
+
+import javax.swing.ImageIcon;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+
+@SuppressWarnings("serial")
+public class StatusBar extends JPanel {
+
+    // some of this code is inspired by the book
+    // Swing Hacks: Tips & Tools for Building Killer GUIs
+    // By Joshua Marinacci, Chris Adamson
+    // ISBN: 0-596-00907-0
+    // website: http://www.oreilly.com/catalog/swinghks/
+
+    public static final String PRIMARY_STATUS_PROPERTY = "primaryStatus";
+    
+    private Dimension preferredSize;
+    
+    private String primaryStatus = "";
+    private JLabel primaryStatusLabel;
+    private JLabel iconLabel;
+    
+    public StatusBar() {
+        super();
+        setLayout(new BorderLayout(0, 0));
+        
+        primaryStatusLabel = new JLabel(primaryStatus);
+        primaryStatusLabel.setName("primaryStatusLabel");
+        primaryStatusLabel.setFont(getFont().deriveFont(10.0f));
+        primaryStatusLabel.setHorizontalAlignment(JLabel.LEADING);
+        primaryStatusLabel.setVerticalAlignment(JLabel.CENTER);
+
+        add(primaryStatusLabel, BorderLayout.WEST);
+        
+        iconLabel = new JLabel("");
+        ImageIcon grip = new ImageIcon(getClass().getResource("/icons/resize-grip.png"));
+        iconLabel.setIcon(grip);
+
+        iconLabel.setMinimumSize(new Dimension(grip.getIconWidth() + 1, grip.getIconHeight()));
+        iconLabel.setPreferredSize(new Dimension(grip.getIconWidth() + 1, grip.getIconHeight()));
+        iconLabel.setVerticalAlignment(JLabel.BOTTOM);
+
+        add(iconLabel, BorderLayout.EAST);
+        preferredSize = new Dimension(700, grip.getIconHeight() + 5);
+    }
+    
+    @Override
+    @Transient
+    public Dimension getMinimumSize() {
+        if (isMinimumSizeSet()) {
+            return super.getMinimumSize();
+        }
+        return preferredSize;
+    }
+    
+    @Override
+    @Transient
+    public Dimension getPreferredSize() {
+        if (isPreferredSizeSet()) {
+            return super.getPreferredSize();
+        }
+        return preferredSize;
+    }
+    
+    public void setPrimaryStatus(String primaryStatus) {
+        if (primaryStatus == null) throw new NullPointerException();
+        
+        String oldPrimaryStatus = this.primaryStatus;
+        this.primaryStatus = primaryStatus;
+        primaryStatusLabel.setText(" " + primaryStatus);
+        
+        firePropertyChange(PRIMARY_STATUS_PROPERTY, oldPrimaryStatus, this.primaryStatus);
+        repaint();
+    }
+
+    public String getPrimaryStatus() {
+        return primaryStatus;
+    }
+        
+    public static void main(String[] args) {
+        SwingUtilities.invokeLater(new Runnable() {
+            
+            @Override
+            public void run() {
+                JFrame frame = new JFrame();
+                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+                frame.getContentPane().setLayout(new BorderLayout());
+                
+                StatusBar statusBar = new StatusBar();
+                frame.getContentPane().add(statusBar, BorderLayout.SOUTH);
+                
+                frame.setSize(500, 500);
+                frame.setVisible(true);
+            }
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/ThermostatTable.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,91 @@
+/*
+ * 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.swing.components;
+
+import java.awt.Dimension;
+
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.table.DefaultTableModel;
+
+@SuppressWarnings("serial")
+public class ThermostatTable extends JTable {
+    
+    private ThermostatTableColumnResizer resizer;
+    
+    public ThermostatTable() {
+        this((DefaultTableModel) null);
+    }
+    
+    public ThermostatTable(int rowHeight) {
+        this((DefaultTableModel) null, rowHeight);
+    }
+    
+    public ThermostatTable(DefaultTableModel model) {
+        this((DefaultTableModel) model, 25);
+    }
+    
+    public ThermostatTable(DefaultTableModel model, int rowHeight) {
+        super(model);
+
+        setRowHeight(rowHeight);
+        
+        setIntercellSpacing(new Dimension(0, 0));
+        
+        setFillsViewportHeight(true);
+        setAutoCreateRowSorter(true);
+        
+        setDefaultRenderer(Object.class, new ThermostatTableRenderer());
+        setDefaultRenderer(Double.class, new ThermostatTableRenderer());
+        setDefaultRenderer(Long.class, new ThermostatTableRenderer());
+        setDefaultRenderer(String.class, new ThermostatTableRenderer());
+        setDefaultRenderer(Integer.class, new ThermostatTableRenderer());
+        
+        this.resizer = new ThermostatTableColumnResizer(this);
+    }
+    
+    public void repackCells() {
+        resizer.resize();
+        revalidate();
+    }
+    
+    public JScrollPane wrap() {        
+        JScrollPane scrollPane = new JScrollPane(this);
+        repackCells();
+        return scrollPane;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/ThermostatTableColumnResizer.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.swing.components;
+
+import java.awt.Component;
+
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableColumnModel;
+
+class ThermostatTableColumnResizer {
+    
+    // reference Swing Hacks book:
+    // http://shop.oreilly.com/product/9780596009076.do
+    
+    private ThermostatTable table;
+    
+    public ThermostatTableColumnResizer(ThermostatTable table) {
+        this.table = table;
+    }
+    
+    public void resize() {
+        TableColumnModel model = table.getColumnModel();
+        for (int column = 0; column < table.getColumnCount(); column++ ) {
+            int maxWidth = 0;
+            for (int row = 0; row < table.getRowCount(); row++ ) {
+                TableCellRenderer renderer = table.getCellRenderer(row, column);
+                Object value = table.getValueAt(row, column);
+                Component component = renderer.getTableCellRendererComponent(table, value, false, false, row, column);
+                maxWidth = Math.max(component.getPreferredSize().width, maxWidth);
+            }
+            
+            TableColumn tableColumn = model.getColumn(column);
+            TableCellRenderer headerRenderer = tableColumn.getHeaderRenderer();
+            if (headerRenderer == null) {
+                headerRenderer = table.getTableHeader().getDefaultRenderer(); 
+            }
+            
+            Object headerValue = tableColumn.getHeaderValue();
+            Component headerComponent = headerRenderer.getTableCellRendererComponent(table, headerValue, false, false, 0, column);
+            maxWidth = Math.max(maxWidth, headerComponent.getPreferredSize().width);
+            
+            tableColumn.setPreferredWidth(maxWidth);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/ThermostatTableRenderer.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,68 @@
+/*
+ * 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.swing.components;
+
+import java.awt.Component;
+
+import javax.swing.JTable;
+import javax.swing.table.DefaultTableCellRenderer;
+
+import com.redhat.thermostat.client.ui.Palette;
+
+@SuppressWarnings("serial")
+public class ThermostatTableRenderer extends DefaultTableCellRenderer {
+
+    @Override
+    public Component getTableCellRendererComponent(JTable table, Object value,
+            boolean isSelected, boolean hasFocus, int row, int column) {
+
+        Component result = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+        if (result == null || isSelected) {
+            // do nothing
+        } else if (!isEven(row)) {
+            result.setBackground(Palette.LIGHT_GRAY.getColor());
+        } else {
+            result.setBackground(Palette.WHITE.getColor());
+        }
+        
+        return result;
+    }
+
+    private boolean isEven(int row) {
+        return row % 2 == 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/ToolbarButton.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.swing.components;
+
+import javax.swing.AbstractButton;
+
+public interface ToolbarButton {
+    AbstractButton getToolbarButton();
+    void toggleText(boolean showText);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/ToolbarButtonBorder.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.components;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.io.Serializable;
+
+import javax.swing.AbstractButton;
+import javax.swing.ButtonModel;
+import javax.swing.plaf.UIResource;
+
+import com.redhat.thermostat.client.ui.Palette;
+
+@SuppressWarnings("serial")
+public class ToolbarButtonBorder extends DebugBorder implements UIResource, Serializable {
+
+    public ToolbarButtonBorder(ToolbarButton button) {
+        // TODO Auto-generated constructor stub
+    }
+    
+    @Override
+    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
+        
+        AbstractButton button = (AbstractButton) c;
+        ButtonModel model = button.getModel();
+        
+        Color colour = Palette.GRAY.getColor();
+        if (model.isPressed()) {
+            colour = Palette.PALE_GRAY.getColor();
+        } else if (model.isRollover()) {
+            colour = Palette.DARK_GRAY.getColor();
+        }
+        
+        if (model.isRollover() || model.isPressed() || model.isSelected()) {
+            GraphicsUtils graphicsUtils = GraphicsUtils.getInstance();
+            Graphics2D graphics = graphicsUtils.createAAGraphics(g);            
+
+            Shape shape = graphicsUtils.getRoundShape(width - 1, height - 1);
+
+            graphics.setColor(colour);
+            graphics.translate(x, y);
+            graphics.draw(shape);
+
+            graphics.dispose();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/ValueField.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.components;
+
+import javax.swing.JEditorPane;
+import javax.swing.UIManager;
+
+/**
+ * A custom swing component meant for showing values. Use it like you would use
+ * any other JTextComponent.
+ */
+@SuppressWarnings("serial")
+public class ValueField extends JEditorPane {
+
+    public ValueField(String text) {
+        setText(text);
+        setBorder(null);
+        setOpaque(false);
+        setBackground(UIManager.getColor("Label.background"));
+        setForeground(UIManager.getColor("Label.foreground"));
+        setFont(UIManager.getFont("Label.font"));
+        setEditable(false);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/models/LongRange.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,60 @@
+/*
+ * 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.swing.components.models;
+
+public class LongRange {
+
+    long min;
+    long max;
+    
+    public void setMax(long max) {
+        this.max = max;
+    }
+    
+    public long getMax() {
+        return max;
+    }
+    
+    public void setMin(long min) {
+        this.min = min;
+    }
+    
+    
+    public long getMin() {
+        return min;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/models/LongRangeNormalizer.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.components.models;
+
+public class LongRangeNormalizer {
+
+    private long minNormalized;
+    
+    private long maxNormalized;
+ 
+    private long value;
+
+    private LongRange range;
+    
+    public LongRangeNormalizer(LongRange range) {
+        this.range = range;
+    }
+
+    public void setMaxNormalized(long maxNormalized) {
+        this.maxNormalized = maxNormalized;
+    }
+    
+    public void setMinNormalized(long minNormalized) {
+        this.minNormalized = minNormalized;
+    }
+    
+    public long getValue() {
+        return value;
+    }
+
+    public void setValue(long newValue) {
+        this.value = newValue;
+    }
+    
+    public long getMaxNormalized() {
+        return maxNormalized;
+    }
+    
+    public long getMinNormalized() {
+        return minNormalized;
+    }
+    
+    public long getValueNormalized() {
+        double normalized = ((value - range.min) * (double)(maxNormalized - minNormalized)/(range.max - range.min)) + minNormalized;
+        return Math.round(normalized);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/models/NullSelectionModel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.components.models;
+
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionListener;
+
+public class NullSelectionModel implements ListSelectionModel {
+
+    @Override
+    public void setSelectionInterval(int index0, int index1) {
+    }
+
+    @Override
+    public void addSelectionInterval(int index0, int index1) {
+    }
+
+    @Override
+    public void removeSelectionInterval(int index0, int index1) {        
+    }
+
+    @Override
+    public int getMinSelectionIndex() {
+        return 0;
+    }
+
+    @Override
+    public int getMaxSelectionIndex() {
+        return 0;
+    }
+
+    @Override
+    public boolean isSelectedIndex(int index) {
+        return false;
+    }
+
+    @Override
+    public int getAnchorSelectionIndex() {
+        return 0;
+    }
+
+    @Override
+    public void setAnchorSelectionIndex(int index) {        
+    }
+
+    @Override
+    public int getLeadSelectionIndex() {
+        return -1;
+    }
+
+    @Override
+    public void setLeadSelectionIndex(int index) {
+    }
+
+    @Override
+    public void clearSelection() {
+    }
+
+    @Override
+    public boolean isSelectionEmpty() {
+        return true;
+    }
+
+    @Override
+    public void insertIndexInterval(int index, int length, boolean before) {
+    }
+
+    @Override
+    public void removeIndexInterval(int index0, int index1) {
+    }
+
+    @Override
+    public void setValueIsAdjusting(boolean valueIsAdjusting) {
+    }
+
+    @Override
+    public boolean getValueIsAdjusting() {
+        return false;
+    }
+
+    @Override
+    public void setSelectionMode(int selectionMode) {
+    }
+
+    @Override
+    public int getSelectionMode() {
+        return -1;
+    }
+
+    @Override
+    public void addListSelectionListener(ListSelectionListener x) {        
+    }
+
+    @Override
+    public void removeListSelectionListener(ListSelectionListener x) {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/AboutDialog.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.swing.internal;
+
+import java.awt.Cursor;
+import java.awt.Desktop;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.net.URI;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.swing.GroupLayout;
+import javax.swing.GroupLayout.Alignment;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.LayoutStyle.ComponentPlacement;
+import javax.swing.SwingConstants;
+import javax.swing.SwingWorker;
+import javax.swing.border.TitledBorder;
+
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.swing.IconResource;
+import com.redhat.thermostat.client.swing.UIResources;
+import com.redhat.thermostat.common.ApplicationInfo;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+
+public class AboutDialog extends JDialog {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+    private static final long serialVersionUID = -7611616871710076514L;
+
+    private static final Logger logger = LoggingUtils.getLogger(AboutDialog.class);
+
+    private String name;
+    private String description;
+    private String version;
+    private Icon icon;
+    private String copyright;
+    private String license;
+    private String website;
+    private String email;
+    
+    /**
+     * Create the dialog.
+     * @param applicationInfo 
+     */
+    public AboutDialog(ApplicationInfo appInfo) {
+        setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+        setResizable(false);
+        
+        name = appInfo.getName();
+        description = appInfo.getDescription();
+        version = appInfo.getVersion().getVersionNumber();
+        icon = IconResource.QUESTION.getIcon();
+        copyright = appInfo.getCopyright();
+        license = appInfo.getLicenseSummary();
+        website = appInfo.getWebsite();
+        email = appInfo.getEmail();
+        
+        initComponents();
+    }
+    
+    private void initComponents() {
+        setBounds(100, 100, 450, 338);
+        
+        UIResources res = UIResources.getInstance();
+        
+        JPanel panel = new JPanel();
+        panel.setBorder(new TitledBorder(""));
+        
+        JButton closeButton = new JButton(translator.localize(LocaleResources.BUTTON_CLOSE));
+        closeButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                AboutDialog.this.setVisible(false);
+                AboutDialog.this.dispose();  
+            }
+        });
+        
+        GroupLayout groupLayout = new GroupLayout(getContentPane());
+        groupLayout.setHorizontalGroup(
+            groupLayout.createParallelGroup(Alignment.TRAILING)
+                .addGroup(groupLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
+                        .addComponent(closeButton, GroupLayout.PREFERRED_SIZE, 92, GroupLayout.PREFERRED_SIZE)
+                        .addComponent(panel, GroupLayout.DEFAULT_SIZE, 424, Short.MAX_VALUE))
+                    .addContainerGap())
+        );
+        groupLayout.setVerticalGroup(
+            groupLayout.createParallelGroup(Alignment.LEADING)
+                .addGroup(groupLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addComponent(panel, GroupLayout.DEFAULT_SIZE, 245, Short.MAX_VALUE)
+                    .addGap(18)
+                    .addComponent(closeButton)
+                    .addGap(9))
+        );
+        
+        JLabel iconLabel = new JLabel("");
+        iconLabel.setHorizontalAlignment(SwingConstants.CENTER);
+        
+        iconLabel.setIcon(icon);
+        
+        JLabel versionLabel = new JLabel(version);
+        versionLabel.setFont(res.footerFont());
+        versionLabel.setHorizontalAlignment(SwingConstants.CENTER);
+        
+        JLabel nameLabel = new JLabel(name);
+        nameLabel.setFont(res.headerFont());
+        nameLabel.setHorizontalAlignment(SwingConstants.CENTER);
+        
+        JLabel descriptionLabel = new JLabel(description);
+        descriptionLabel.setHorizontalAlignment(SwingConstants.CENTER);
+        descriptionLabel.setFont(res.standardFont());
+        
+        JLabel homePageLabel = new JLabel(website);
+        homePageLabel.setForeground(res.hyperlinkColor());
+        homePageLabel.setHorizontalAlignment(SwingConstants.CENTER);
+        homePageLabel.setFont(res.footerFont());        
+        homePageLabel.addMouseListener(new Browse(homePageLabel));
+
+        JLabel copyrightLabel = new JLabel(copyright);
+        copyrightLabel.setHorizontalAlignment(SwingConstants.CENTER);
+        copyrightLabel.setFont(res.footerFont());
+        
+        JLabel licenseString = new JLabel(license);
+        licenseString.setHorizontalAlignment(SwingConstants.CENTER);
+        licenseString.setFont(res.footerFont());
+        
+        JLabel emailLabel = new JLabel(email);
+        emailLabel.setHorizontalAlignment(SwingConstants.CENTER);
+        emailLabel.setForeground(res.hyperlinkColor());
+        emailLabel.setFont(res.footerFont());
+        emailLabel.addMouseListener(new Mailer(emailLabel));
+        
+        GroupLayout gl_panel = new GroupLayout(panel);
+        gl_panel.setHorizontalGroup(
+            gl_panel.createParallelGroup(Alignment.TRAILING)
+                .addGroup(gl_panel.createSequentialGroup()
+                    .addContainerGap()
+                    .addGroup(gl_panel.createParallelGroup(Alignment.LEADING)
+                        .addComponent(iconLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 398, Short.MAX_VALUE)
+                        .addComponent(nameLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 398, Short.MAX_VALUE)
+                        .addComponent(versionLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 398, Short.MAX_VALUE)
+                        .addComponent(descriptionLabel, GroupLayout.DEFAULT_SIZE, 398, Short.MAX_VALUE)
+                        .addComponent(copyrightLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 398, Short.MAX_VALUE)
+                        .addComponent(licenseString, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 398, Short.MAX_VALUE)
+                        .addComponent(emailLabel, GroupLayout.DEFAULT_SIZE, 398, Short.MAX_VALUE)
+                        .addComponent(homePageLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 398, Short.MAX_VALUE))
+                    .addContainerGap())
+        );
+        gl_panel.setVerticalGroup(
+            gl_panel.createParallelGroup(Alignment.LEADING)
+                .addGroup(gl_panel.createSequentialGroup()
+                    .addContainerGap()
+                    .addComponent(iconLabel)
+                    .addGap(4)
+                    .addComponent(nameLabel, GroupLayout.DEFAULT_SIZE, 24, Short.MAX_VALUE)
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addComponent(versionLabel, GroupLayout.DEFAULT_SIZE, 13, Short.MAX_VALUE)
+                    .addPreferredGap(ComponentPlacement.UNRELATED)
+                    .addComponent(descriptionLabel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addGap(12)
+                    .addComponent(homePageLabel, GroupLayout.DEFAULT_SIZE, 19, Short.MAX_VALUE)
+                    .addGap(3)
+                    .addComponent(emailLabel, GroupLayout.DEFAULT_SIZE, 19, Short.MAX_VALUE)
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addComponent(copyrightLabel, GroupLayout.DEFAULT_SIZE, 13, Short.MAX_VALUE)
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addComponent(licenseString, GroupLayout.DEFAULT_SIZE, 13, Short.MAX_VALUE)
+                    .addContainerGap())
+        );
+        panel.setLayout(gl_panel);
+        getContentPane().setLayout(groupLayout);
+    }
+    
+    private abstract class HyperLinkAction extends MouseAdapter {
+        
+        private JLabel hyperLinkLabel;
+        public HyperLinkAction(JLabel hyperLinkLabel) {
+            this.hyperLinkLabel = hyperLinkLabel;
+        }
+        
+        @Override
+        public void mouseEntered(MouseEvent e) {
+            hyperLinkLabel.setForeground(UIResources.getInstance().hyperlinkActiveColor());
+            Cursor cursor = new Cursor(Cursor.HAND_CURSOR);
+            setCursor(cursor);
+        }
+        @Override
+        public void mouseExited(MouseEvent e) {
+            hyperLinkLabel.setForeground(UIResources.getInstance().hyperlinkColor());
+            Cursor cursor = new Cursor(Cursor.DEFAULT_CURSOR);
+            setCursor(cursor);
+        }
+        
+        @Override
+        public void mouseClicked(MouseEvent e) {
+            if (Desktop.isDesktopSupported()) {
+                new SwingWorker<Void, Void>() {
+                    @Override
+                    protected Void doInBackground() throws Exception {
+                        doAction();
+                        return null;
+                    }
+                    @Override
+                    protected void done() {
+                        hyperLinkLabel.setForeground(UIResources.getInstance().hyperlinkColor());
+                    }
+                }.execute();
+            }
+        }
+        
+        protected abstract void doAction();
+    }
+    
+    private class Mailer extends HyperLinkAction {
+        public Mailer(JLabel hyperLinkLabel) {
+            super(hyperLinkLabel);
+        }
+
+        @Override
+        protected void doAction() {
+            try {
+                Desktop.getDesktop().mail(new URI("mailto:" + email));
+            } catch (Exception ex) {
+                logger.log(Level.WARNING, "Cannot send mail to Thermosat mail", ex);
+            }
+        }
+    }
+    
+    private class Browse extends HyperLinkAction {
+        public Browse(JLabel hyperLinkLabel) {
+            super(hyperLinkLabel);
+        }
+        
+        @Override
+        protected void doAction() {
+            try {
+                Desktop.getDesktop().browse(new URI(website));
+            } catch (Exception ex) {
+                logger.log(Level.WARNING, "Cannot open Thermostat website URL", ex);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/ChangeableText.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.internal;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class ChangeableText {
+
+    private final Set<TextListener> listeners = new HashSet<TextListener>();
+    private String text;
+
+    public static interface TextListener {
+        public void textChanged(ChangeableText text);
+    }
+
+    public ChangeableText(String text) {
+        this.text = text;
+    }
+
+    public synchronized void setText(String text) {
+        if (this.text.equals(text)) {
+            return;
+        }
+        this.text = text;
+        fireChanged();
+    }
+
+    public synchronized String getText() {
+        return text;
+    }
+
+    public synchronized void addListener(TextListener listener) {
+        this.listeners.add(listener);
+    }
+
+    public synchronized void removeListener(TextListener listener) {
+        this.listeners.remove(listener);
+    }
+
+    private void fireChanged() {
+        for (TextListener listener: listeners) {
+            listener.textChanged(this);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/GUIClientCommand.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,87 @@
+/*
+ * 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.swing.internal;
+
+import org.osgi.framework.BundleContext;
+
+import com.redhat.thermostat.client.osgi.service.ApplicationService;
+import com.redhat.thermostat.client.osgi.service.ContextAction;
+import com.redhat.thermostat.client.swing.internal.osgi.ApplicationServiceProvider;
+import com.redhat.thermostat.client.swing.internal.osgi.ContextActionServiceProvider;
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandException;
+import com.redhat.thermostat.common.cli.OSGiContext;
+import com.redhat.thermostat.common.cli.SimpleCommand;
+
+public class GUIClientCommand extends SimpleCommand implements OSGiContext {
+
+    private BundleContext context;
+    private Main clientMain;
+
+    public GUIClientCommand(Main clientMain) {
+        this.clientMain = clientMain;
+    }
+
+    @Override
+    public void setBundleContext(BundleContext context) {
+        this.context = context;
+    }
+    
+    @Override
+    public void run(CommandContext ctx) throws CommandException {
+        ApplicationService service = new ApplicationServiceProvider();
+        
+        context.registerService(ApplicationService.class.getName(), service, null);
+        context.registerService(ContextAction.class.getName(), new ContextActionServiceProvider(), null);
+        
+        // this blocks, everything else needs to be done before
+        clientMain.run();
+
+        service.getApplicationExecutor().shutdown();
+    }
+
+    @Override
+    public String getName() {
+        return "gui";
+    }
+
+    @Override
+    public boolean isStorageRequired() {
+        return false;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/HostFilterRegistry.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.internal;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+
+import com.redhat.thermostat.client.core.HostFilter;
+import com.redhat.thermostat.common.ThermostatExtensionRegistry;
+
+class HostFilterRegistry extends ThermostatExtensionRegistry<HostFilter> {
+
+    private static final String FILTER = "(" + Constants.OBJECTCLASS + "=" + HostFilter.class.getName() + ")";
+
+    public HostFilterRegistry(BundleContext context) throws InvalidSyntaxException {
+        super(context, FILTER, HostFilter.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/HostIconDecorator.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,105 @@
+/*
+ * 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.swing.internal;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
+import com.redhat.thermostat.client.core.HostFilter;
+import com.redhat.thermostat.client.osgi.service.HostDecorator;
+import com.redhat.thermostat.client.swing.IconResource;
+import com.redhat.thermostat.client.ui.Decorator;
+import com.redhat.thermostat.client.ui.IconDescriptor;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.utils.StreamUtils;
+
+public class HostIconDecorator implements HostDecorator {
+
+    private final HostFilter anyHost = new AnyHostMatcher();
+
+    @Override
+    public Decorator getDecorator() {
+        return new IconDecorator();
+    }
+
+    @Override
+    public HostFilter getFilter() {
+        return anyHost;
+    }
+
+    private static class IconDecorator implements Decorator {
+
+        private final IconDescriptor icon;
+
+        public IconDecorator() {
+            IconDescriptor icon = null;
+            try {
+                InputStream in = new FileInputStream(IconResource.HOST.getPath());
+                icon = new IconDescriptor(ByteBuffer.wrap(StreamUtils.readAll(in)));
+            } catch (IOException ioe) {
+                ioe.printStackTrace();
+            }
+            this.icon = icon;
+        }
+
+        @Override
+        public String getLabel(String originalLabel) {
+            return originalLabel;
+        }
+
+        @Override
+        public IconDescriptor getIconDescriptor() {
+            return icon;
+        }
+
+        @Override
+        public Quadrant getQuadrant() {
+            return Quadrant.MAIN;
+        }
+
+    }
+
+    private static class AnyHostMatcher implements HostFilter {
+        @Override
+        public boolean matches(HostRef toMatch) {
+            return true;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/HostTreeDecoratorRegistry.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.internal;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+
+import com.redhat.thermostat.client.osgi.service.HostDecorator;
+import com.redhat.thermostat.common.ThermostatExtensionRegistry;
+
+class HostTreeDecoratorRegistry extends ThermostatExtensionRegistry<HostDecorator> {
+
+    private static final String FILTER = "(" + Constants.OBJECTCLASS + "=" + HostDecorator.class.getName() + ")";
+
+    public HostTreeDecoratorRegistry(BundleContext context) throws InvalidSyntaxException {
+        super(context, FILTER, HostDecorator.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/Main.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,329 @@
+/*
+ * 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.swing.internal;
+
+import java.awt.EventQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.swing.JOptionPane;
+import javax.swing.JPopupMenu;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+
+import com.redhat.swing.laf.dolphin.DolphinLookAndFeel;
+import com.redhat.thermostat.client.core.views.ClientConfigurationView;
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.osgi.service.ApplicationService;
+import com.redhat.thermostat.client.swing.internal.config.ConnectionConfiguration;
+import com.redhat.thermostat.client.swing.views.ClientConfigurationSwing;
+import com.redhat.thermostat.client.ui.ClientConfigurationController;
+import com.redhat.thermostat.client.ui.MainWindowController;
+import com.redhat.thermostat.client.ui.UiFacadeFactory;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.Constants;
+import com.redhat.thermostat.common.ThreadPoolTimerFactory;
+import com.redhat.thermostat.common.TimerFactory;
+import com.redhat.thermostat.common.appctx.ApplicationContext;
+import com.redhat.thermostat.common.config.ClientPreferences;
+import com.redhat.thermostat.common.config.StartupConfiguration;
+import com.redhat.thermostat.common.dao.DAOFactory;
+import com.redhat.thermostat.common.dao.MongoDAOFactory;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.storage.Connection;
+import com.redhat.thermostat.common.storage.Connection.ConnectionListener;
+import com.redhat.thermostat.common.storage.Connection.ConnectionStatus;
+import com.redhat.thermostat.common.storage.Connection.ConnectionType;
+import com.redhat.thermostat.common.storage.MongoStorageProvider;
+import com.redhat.thermostat.common.storage.StorageProvider;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.utils.keyring.Keyring;
+
+public class Main {
+    
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private static final Logger logger = LoggingUtils.getLogger(Main.class);
+
+    private OSGIUtils serviceProvider;
+    private UiFacadeFactory uiFacadeFactory;
+    private DAOFactory daoFactory;
+    
+    public Main(Keyring keyring, UiFacadeFactory uiFacadeFactory, String[] args) {
+        ClientPreferences prefs = new ClientPreferences(keyring);
+        StartupConfiguration config = new ConnectionConfiguration(prefs);
+        StorageProvider connProv = new MongoStorageProvider(config);
+
+        DAOFactory daoFactory = new MongoDAOFactory(connProv);
+        TimerFactory timerFactory = new ThreadPoolTimerFactory(1);
+
+        init(OSGIUtils.getInstance(), uiFacadeFactory, daoFactory, timerFactory);
+    }
+
+    Main(OSGIUtils serviceProvider, UiFacadeFactory uiFacadeFactory, DAOFactory daoFactory, TimerFactory timerFactory) {
+        init(serviceProvider, uiFacadeFactory, daoFactory, timerFactory);
+    }
+
+    private void init(OSGIUtils serviceProvider, UiFacadeFactory uiFacadeFactory, DAOFactory daoFactory, TimerFactory timerFactory) {
+        this.serviceProvider = serviceProvider;
+        this.uiFacadeFactory = uiFacadeFactory;
+        this.daoFactory = daoFactory;
+        ApplicationContext.getInstance().setTimerFactory(timerFactory);
+    }
+
+    public void run() {
+        EventQueue.invokeLater(new Runnable() {
+
+            @Override
+            public void run() {
+
+                // check if the user has other preferences...
+                // not that there is any reason!
+                String laf = System.getProperty("swing.defaultlaf");
+                if (laf == null) {
+                    try {
+                        UIManager.setLookAndFeel(new DolphinLookAndFeel());
+                    } catch (UnsupportedLookAndFeelException e) {
+                        logger.log(Level.WARNING, "cannot use DolphinLookAndFeel");
+                    }
+                }
+
+                // TODO: move them in an appropriate place
+                JPopupMenu.setDefaultLightWeightPopupEnabled(false);
+                UIManager.getDefaults().put("OptionPane.buttonOrientation", SwingConstants.RIGHT);
+                UIManager.getDefaults().put("OptionPane.isYesLast", true);
+                UIManager.getDefaults().put("OptionPane.sameSizeButtons", true);
+                
+                showGui();
+            }
+
+        });
+
+        try {
+            uiFacadeFactory.awaitShutdown();
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+        }
+    }
+
+    private void showGui() {
+        ApplicationService appSrv = serviceProvider.getService(ApplicationService.class);
+        final ExecutorService service = appSrv.getApplicationExecutor();
+        service.execute(new ConnectorSetup(service));
+    }
+    
+    private class ConnectorSetup implements Runnable {
+        
+        private ExecutorService service;
+        public ConnectorSetup(ExecutorService service) {
+            this.service = service;
+        }
+        
+        @Override
+        public void run() {
+            
+            Connection connection = daoFactory.getConnection();
+            connection.setType(ConnectionType.LOCAL);
+            ConnectionListener connectionListener = new ConnectionHandler(connection, service);
+            connection.addListener(connectionListener);
+            try {
+                connection.connect();
+            } catch (Throwable t) {
+                logger.log(Level.WARNING, "connection attempt failed: ", t);
+            }
+        }
+    }
+    
+    private class Connector implements Runnable {
+        private Connection connection;
+        Connector(Connection connection) {
+            this.connection = connection;
+        }
+        
+        @Override
+        public void run() {
+            try {
+                connection.connect();
+            } catch (Throwable t) {
+                logger.log(Level.WARNING, "connection attempt failed: ", t);
+            }
+        }
+    }
+    
+    private class ConnectionAttemp implements Runnable {
+        private Connection connection;
+        private ExecutorService service;
+        public ConnectionAttemp(Connection connection, ExecutorService service) {
+            this.connection = connection;
+            this.service = service;
+        }
+        
+        @Override
+        public void run() {
+            Object[] options = {
+                    translator.localize(LocaleResources.CONNECTION_WIZARD),
+                    translator.localize(LocaleResources.CONNECTION_QUIT),
+            };
+            int n = JOptionPane
+                    .showOptionDialog(
+                            null,
+                            translator.localize(LocaleResources.CONNECTION_FAILED_TO_CONNECT_DESCRIPTION),
+                            translator.localize(LocaleResources.CONNECTION_FAILED_TO_CONNECT_TITLE),
+                            JOptionPane.OK_CANCEL_OPTION,
+                            JOptionPane.ERROR_MESSAGE, null, options,
+                            options[0]);
+
+            switch (n) {
+
+            case JOptionPane.CANCEL_OPTION:
+            case JOptionPane.CLOSED_OPTION:
+            case JOptionPane.NO_OPTION:
+                uiFacadeFactory
+                        .shutdown(Constants.EXIT_UNABLE_TO_CONNECT_TO_DATABASE);
+                break;
+
+            case JOptionPane.YES_OPTION:
+            default:
+                createPreferencesDialog(connection, service);
+                break;
+            }
+        }
+    }
+    
+    private void connect(Connection connection, ExecutorService service) {
+        service.execute(new Connector(connection));
+    }
+    
+    private class ConfigDialogListener implements ActionListener<ClientConfigurationView.Action> {
+        private Connection connection;
+        private ExecutorService service;
+        public ConfigDialogListener(Connection connection, ExecutorService service) {
+            this.connection = connection;
+            this.service = service;
+        }
+        
+        @Override
+        public void actionPerformed(ActionEvent<ClientConfigurationView.Action> actionEvent) {
+            switch (actionEvent.getActionId()) {
+            case CLOSE_CANCEL:
+                uiFacadeFactory.shutdown(Constants.EXIT_UNABLE_TO_CONNECT_TO_DATABASE);
+                break;
+            
+            case CLOSE_ACCEPT:
+            default:
+                connect(connection, service);
+                break;
+            }
+        }
+    }
+    
+    private void createPreferencesDialog(final Connection connection, final ExecutorService service) {
+
+        ClientPreferences prefs = new ClientPreferences(OSGIUtils.getInstance().getService(Keyring.class));
+        ClientConfigurationView configDialog = new ClientConfigurationSwing();
+        ClientConfigurationController controller =
+                new ClientConfigurationController(prefs, configDialog);
+        
+        configDialog.addListener(new ConfigDialogListener(connection, service));
+        controller.showDialog();
+    }
+    
+    private class ConnectionHandler implements ConnectionListener {
+        private boolean retry;
+        private Connection connection;
+        private ExecutorService service;
+        public ConnectionHandler(Connection connection, ExecutorService service) {
+            this.connection = connection;
+            this.retry = true;
+            this.service = service;
+        }
+        
+        private void showConnectionAttemptWarning() {
+            SwingUtilities.invokeLater(new ConnectionAttemp(connection, service));
+        }
+        
+        @Override
+        public void changed(ConnectionStatus newStatus) {
+            if (newStatus == ConnectionStatus.CONNECTED) {
+                
+                // register the storage, so other services can request it
+                daoFactory.registerDAOsAndStorageAsOSGiServices();
+                uiFacadeFactory.setHostInfoDao(daoFactory.getHostInfoDAO());
+                uiFacadeFactory.setCpuStatDao(daoFactory.getCpuStatDAO());
+                uiFacadeFactory.setMemoryStatDao(daoFactory.getMemoryStatDAO());
+                uiFacadeFactory.setNetworkInfoDao(daoFactory.getNetworkInterfaceInfoDAO());
+
+                uiFacadeFactory.setVmInfoDao(daoFactory.getVmInfoDAO());
+                uiFacadeFactory.setVmCpuStatDao(daoFactory.getVmCpuStatDAO());
+                uiFacadeFactory.setVmMemoryStatDao(daoFactory.getVmMemoryStatDAO());
+                uiFacadeFactory.setVmGcStatDao(daoFactory.getVmGcStatDAO());
+
+                showMainWindow();
+            } else if (newStatus == ConnectionStatus.FAILED_TO_CONNECT) {
+                if (retry) {
+                    retry = false;
+                    showConnectionAttemptWarning();
+                } else {
+                    JOptionPane.showMessageDialog(
+                            null,
+                            translator.localize(LocaleResources.CONNECTION_FAILED_TO_CONNECT_DESCRIPTION),
+                            translator.localize(LocaleResources.CONNECTION_FAILED_TO_CONNECT_TITLE),
+                            JOptionPane.ERROR_MESSAGE);
+                    uiFacadeFactory.shutdown(Constants.EXIT_UNABLE_TO_CONNECT_TO_DATABASE);
+                }
+            }
+        }
+    }
+
+
+    private void showMainWindow() {
+        SwingUtilities.invokeLater(new ShowMainWindow());
+    }
+    
+    private class ShowMainWindow implements Runnable {
+        @Override
+        public void run() {
+            MainWindowController mainController = uiFacadeFactory.getMainWindow();
+            mainController.showMainMainWindow();                        
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.internal;
+
+import java.awt.event.MouseEvent;
+import java.util.List;
+
+import com.redhat.thermostat.client.core.HostFilter;
+import com.redhat.thermostat.client.core.VmFilter;
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.osgi.service.HostDecorator;
+import com.redhat.thermostat.client.osgi.service.MenuAction;
+import com.redhat.thermostat.client.osgi.service.VMContextAction;
+import com.redhat.thermostat.client.osgi.service.VmDecorator;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.HostsVMsLoader;
+import com.redhat.thermostat.common.dao.Ref;
+
+public interface MainView {
+
+    enum Action {
+        VISIBLE,
+        HIDDEN,
+        HOST_VM_TREE_FILTER,
+        HOST_VM_SELECTION_CHANGED,
+        SHOW_AGENT_CONFIG,
+        SHOW_CLIENT_CONFIG,
+        SWITCH_HISTORY_MODE,
+        SHOW_ABOUT_DIALOG,
+        SHUTDOWN,
+        SHOW_VM_CONTEXT_MENU,
+        VM_CONTEXT_ACTION,
+    }
+
+    void addActionListener(ActionListener<Action> capture);
+
+    void updateTree(List<HostFilter> hostFilters, List<VmFilter> vmFilters,
+            List<HostDecorator> hostDecorators, List<VmDecorator> vmDecorators,
+            HostsVMsLoader any);
+
+    String getHostVmTreeFilterText();
+    
+    void setWindowTitle(String title);
+
+    void showMainWindow();
+
+    void hideMainWindow();
+
+    Ref getSelectedHostOrVm();
+
+    void setSubView(BasicView view);
+
+    void setStatusBarPrimaryStatus(String primaryStatus);
+    
+    /**
+     * Adds a menu item to the window. Assumes the menu path is valid (has a
+     * non-zero length) and doesn't collide with existing menus.
+     */
+    void addMenu(MenuAction action);
+
+    /**
+     * Removes a menu item to the window. Assumes the menu path is valid (has a
+     * non-zero length) and doesn't collide with existing menus.
+     */
+    void removeMenu(MenuAction action);
+
+    void showVMContextActions(List<VMContextAction> actions, MouseEvent e);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImpl.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,511 @@
+/*
+ * 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.swing.internal;
+
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.osgi.framework.InvalidSyntaxException;
+
+import com.redhat.thermostat.client.core.HostFilter;
+import com.redhat.thermostat.client.core.VmFilter;
+import com.redhat.thermostat.client.core.views.AgentInformationDisplayView;
+import com.redhat.thermostat.client.core.views.AgentInformationViewProvider;
+import com.redhat.thermostat.client.core.views.ClientConfigViewProvider;
+import com.redhat.thermostat.client.core.views.ClientConfigurationView;
+import com.redhat.thermostat.client.osgi.service.HostDecorator;
+import com.redhat.thermostat.client.osgi.service.MenuAction;
+import com.redhat.thermostat.client.osgi.service.VMContextAction;
+import com.redhat.thermostat.client.osgi.service.VmDecorator;
+import com.redhat.thermostat.client.swing.internal.MainView.Action;
+import com.redhat.thermostat.client.ui.AgentInformationDisplayController;
+import com.redhat.thermostat.client.ui.AgentInformationDisplayModel;
+import com.redhat.thermostat.client.ui.ClientConfigurationController;
+import com.redhat.thermostat.client.ui.HostInformationController;
+import com.redhat.thermostat.client.ui.HostVmFilter;
+import com.redhat.thermostat.client.ui.MainWindowController;
+import com.redhat.thermostat.client.ui.SummaryController;
+import com.redhat.thermostat.client.ui.UiFacadeFactory;
+import com.redhat.thermostat.client.ui.VmInformationController;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ApplicationInfo;
+import com.redhat.thermostat.common.DefaultHostsVMsLoader;
+import com.redhat.thermostat.common.HostsVMsLoader;
+import com.redhat.thermostat.common.ThermostatExtensionRegistry;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.Timer.SchedulingType;
+import com.redhat.thermostat.common.appctx.ApplicationContext;
+import com.redhat.thermostat.common.config.ClientPreferences;
+import com.redhat.thermostat.common.dao.HostInfoDAO;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.Ref;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.utils.keyring.Keyring;
+
+public class MainWindowControllerImpl implements MainWindowController {
+
+    private static final Logger logger = LoggingUtils.getLogger(MainWindowControllerImpl.class);
+
+    private final CopyOnWriteArrayList<HostFilter> hostFilters = new CopyOnWriteArrayList<>();
+    private final CopyOnWriteArrayList<VmFilter> vmFilters = new CopyOnWriteArrayList<>();
+
+    private final CopyOnWriteArrayList<HostDecorator> hostTreeDecorators = new CopyOnWriteArrayList<>();
+    private final CopyOnWriteArrayList<VmDecorator> vmTreeDecorators = new CopyOnWriteArrayList<>();
+
+    private Timer backgroundUpdater;
+
+    private MainView view;
+
+    private final HostInfoDAO hostsDAO;
+    private final VmInfoDAO vmsDAO;
+
+    private ApplicationInfo appInfo;
+
+    private UiFacadeFactory facadeFactory;
+
+    private MenuRegistry menuRegistry;
+    private ActionListener<ThermostatExtensionRegistry.Action> menuListener =
+            new ActionListener<ThermostatExtensionRegistry.Action>()
+    {
+        @Override
+        public void actionPerformed(
+            ActionEvent<ThermostatExtensionRegistry.Action> actionEvent) {
+            MenuAction action = (MenuAction) actionEvent.getPayload();
+
+            switch (actionEvent.getActionId()) {
+            case SERVICE_ADDED:
+                view.addMenu(action);
+                break;
+
+            case SERVICE_REMOVED:
+                view.removeMenu(action);
+                break;
+
+            default:
+                logger.log(Level.WARNING, "received unknown event from MenuRegistry: " +
+                                           actionEvent.getActionId());
+                break;
+            }
+        }
+    };
+
+    private HostVmFilter searchFilter;
+    private VmFilterRegistry vmFilterRegistry;
+    private HostFilterRegistry hostFilterRegistry;
+
+    private ActionListener<ThermostatExtensionRegistry.Action> hostFilterListener = new UpdateListAndTree<>(HostFilter.class, hostFilters);
+    private ActionListener<ThermostatExtensionRegistry.Action> vmFilterListener = new UpdateListAndTree<>(VmFilter.class, vmFilters);
+
+    private HostTreeDecoratorRegistry hostDecoratorRegistry;
+    private VMTreeDecoratorRegistry vmDecoratorRegistry;
+
+    private ActionListener<ThermostatExtensionRegistry.Action> hostDecoratorListener = new UpdateListAndTree<>(HostDecorator.class, hostTreeDecorators);
+    private ActionListener<ThermostatExtensionRegistry.Action> vmDecoratorListener = new UpdateListAndTree<>(VmDecorator.class, vmTreeDecorators);
+
+    private VMInformationRegistry vmInfoRegistry;
+    private ActionListener<ThermostatExtensionRegistry.Action> vmInfoRegistryListener =
+            new ActionListener<ThermostatExtensionRegistry.Action> ()
+    {
+        public void actionPerformed(com.redhat.thermostat.common.ActionEvent<ThermostatExtensionRegistry.Action>
+                                    actionEvent)
+        {
+            updateView();
+        };
+    };
+            
+    private boolean showHistory;
+
+    private VmInformationControllerProvider vmInfoControllerProvider;
+
+    public MainWindowControllerImpl(UiFacadeFactory facadeFactory, MainView view, RegistryFactory registryFactory, HostInfoDAO hostsDao, VmInfoDAO vmsDAO)
+    {
+        try {
+            vmFilterRegistry = registryFactory.createVmFilterRegistry();
+            hostFilterRegistry = registryFactory.createHostFilterRegistry();
+            hostDecoratorRegistry = registryFactory.createHostTreeDecoratorRegistry();
+            vmDecoratorRegistry = registryFactory.createVMTreeDecoratorRegistry();
+            menuRegistry = registryFactory.createMenuRegistry();
+            vmInfoRegistry = registryFactory.createVMInformationRegistry();
+            
+        } catch (InvalidSyntaxException e) {
+            throw new RuntimeException(e);
+        }
+
+        searchFilter = new HostVmFilter();
+        hostFilters.add(searchFilter);
+        vmFilters.add(searchFilter);
+        
+        this.facadeFactory = facadeFactory;
+
+        this.hostsDAO = hostsDao;
+        this.vmsDAO = vmsDAO;
+
+        initView(view);
+
+        vmInfoControllerProvider = new VmInformationControllerProvider();
+
+        appInfo = new ApplicationInfo();
+        view.setWindowTitle(appInfo.getName());
+        initializeTimer();
+
+        updateView();
+
+        installListenersAndStartRegistries();
+    }
+
+    /**
+     * This method is for testing purposes only
+     */
+    HostVmFilter getSearchFilter() {
+        return searchFilter;
+    }
+    
+    /**
+     * This method is for testing purposes only
+     */ 
+    List<VmDecorator> getVmTreeDecorators() {
+        return vmTreeDecorators;
+    }
+    
+    /**
+     * This method is for testing purposes only
+     */
+    ActionListener<ThermostatExtensionRegistry.Action> getMenuListener() {
+        return menuListener;
+    }
+    
+    private void initializeTimer() {
+        ApplicationContext ctx = ApplicationContext.getInstance();
+        backgroundUpdater = ctx.getTimerFactory().createTimer();
+        backgroundUpdater.setAction(new Runnable() {
+            @Override
+            public void run() {
+                doUpdateTreeAsync();
+            }
+        });
+        backgroundUpdater.setInitialDelay(0);
+        backgroundUpdater.setDelay(3);
+        backgroundUpdater.setTimeUnit(TimeUnit.SECONDS);
+        backgroundUpdater.setSchedulingType(SchedulingType.FIXED_RATE);
+    }
+
+    private void startBackgroundUpdates() {
+        backgroundUpdater.start();
+    }
+
+    public void stopBackgroundUpdates() {
+        backgroundUpdater.stop();
+    }
+
+    @Override
+    public void setHostVmTreeFilter(String filter) {
+        this.searchFilter.setFilter(filter);
+        doUpdateTreeAsync();
+    }
+
+    public void doUpdateTreeAsync() {
+        HostsVMsLoader loader = new DefaultHostsVMsLoader(hostsDAO, vmsDAO, !showHistory);
+        view.updateTree(hostFilters, vmFilters, hostTreeDecorators, vmTreeDecorators, loader);
+    }
+
+    private void initView(MainView mainView) {
+        this.view = mainView;
+        mainView.addActionListener(new ActionListener<MainView.Action>() {
+
+            @Override
+            public void actionPerformed(ActionEvent<MainView.Action> evt) {
+                MainView.Action action = evt.getActionId();
+                switch (action) {
+                case VISIBLE:
+                    startBackgroundUpdates();
+                    break;
+                case HIDDEN:
+                    stopBackgroundUpdates();
+                    break;
+                case HOST_VM_SELECTION_CHANGED:
+                    updateView();
+                    break;
+                case HOST_VM_TREE_FILTER:
+                    String filter = view.getHostVmTreeFilterText();
+                    setHostVmTreeFilter(filter);
+                    break;
+                case SHOW_AGENT_CONFIG:
+                    showAgentConfiguration();
+                    break;
+                case SHOW_CLIENT_CONFIG:
+                    showConfigureClientPreferences();
+                    break;
+                case SWITCH_HISTORY_MODE:
+                    switchHistoryMode();
+                    break;
+                case SHOW_ABOUT_DIALOG:
+                    showAboutDialog();
+                    break;
+                case SHOW_VM_CONTEXT_MENU:
+                    showContextMenu(evt);
+                    break;
+                case VM_CONTEXT_ACTION:
+                    handleVMHooks(evt);
+                    break;
+                case SHUTDOWN:
+                    shutdownApplication();
+                    break;
+                default:
+                    throw new IllegalStateException("unhandled action");
+                }
+            }
+
+        });
+    }
+
+    private void shutdownApplication() {
+        uninstallListenersAndStopRegistries();
+
+        view.hideMainWindow();
+        ApplicationContext.getInstance().getTimerFactory().shutdown();
+        shutdownOSGiFramework();
+    }
+
+    private void installListenersAndStartRegistries() {
+        menuRegistry.addActionListener(menuListener);
+        menuRegistry.start();
+
+        hostFilterRegistry.addActionListener(hostFilterListener);
+        hostFilterRegistry.start();
+
+        vmFilterRegistry.addActionListener(vmFilterListener);
+        vmFilterRegistry.start();
+
+        hostDecoratorRegistry.addActionListener(hostDecoratorListener);
+        hostDecoratorRegistry.start();
+
+        vmDecoratorRegistry.addActionListener(vmDecoratorListener);
+        vmDecoratorRegistry.start();
+
+        vmInfoRegistry.addActionListener(vmInfoRegistryListener);
+        vmInfoRegistry.start();
+    }
+
+    private void uninstallListenersAndStopRegistries() {
+        menuRegistry.removeActionListener(menuListener);
+        menuListener = null;
+        menuRegistry.stop();
+
+        hostFilterRegistry.removeActionListener(hostFilterListener);
+        hostFilterListener = null;
+        hostFilterRegistry.stop();
+
+        vmFilterRegistry.removeActionListener(vmFilterListener);
+        vmFilterListener = null;
+        vmFilterRegistry.stop();
+
+        hostDecoratorRegistry.removeActionListener(hostDecoratorListener);
+        hostDecoratorListener = null;
+        hostDecoratorRegistry.stop();
+
+        vmDecoratorRegistry.removeActionListener(vmDecoratorListener);
+        vmDecoratorListener = null;
+        vmDecoratorRegistry.stop();
+
+        vmInfoRegistry.removeActionListener(vmInfoRegistryListener);
+        vmInfoRegistryListener = null;
+        vmInfoRegistry.stop();
+    }
+
+    private void shutdownOSGiFramework() {
+        facadeFactory.shutdown();
+    }
+
+    private void showContextMenu(ActionEvent<Action> evt) {
+        List<VMContextAction> toShow = new ArrayList<>();
+        VmRef vm = (VmRef) view.getSelectedHostOrVm();
+
+        logger.log(Level.INFO, "registering applicable VMContextActions actions to show");
+
+        for (VMContextAction action : facadeFactory.getVMContextActions()) {
+            if (action.getFilter().matches(vm)) {
+                toShow.add(action);
+            }
+        }
+
+        view.showVMContextActions(toShow, (MouseEvent)evt.getPayload());
+    }
+
+    private void handleVMHooks(ActionEvent<MainView.Action> event) {
+        Object payload = event.getPayload();
+        if (payload instanceof VMContextAction) { 
+            try {
+                VMContextAction action = (VMContextAction) payload;
+                action.execute((VmRef) view.getSelectedHostOrVm());
+            } catch (Throwable error) {
+                logger.log(Level.SEVERE, "");
+            }
+        }
+    }
+    
+    @Override
+    public void showMainMainWindow() {
+        view.showMainWindow();
+    }
+
+    private void showAboutDialog() {
+        AboutDialog aboutDialog = new AboutDialog(appInfo);
+        aboutDialog.setModal(true);
+        aboutDialog.pack();
+        aboutDialog.setVisible(true);
+    }
+
+    private void showAgentConfiguration() {
+        AgentInformationDisplayModel model = new AgentInformationDisplayModel();
+        AgentInformationViewProvider viewProvider = OSGIUtils.getInstance().getService(AgentInformationViewProvider.class);
+        AgentInformationDisplayView view = viewProvider.createView();
+        AgentInformationDisplayController controller = new AgentInformationDisplayController(model, view);
+        controller.showView();
+    }
+
+    private void showConfigureClientPreferences() {
+        ClientPreferences prefs = new ClientPreferences(OSGIUtils.getInstance().getService(Keyring.class));
+        ClientConfigViewProvider viewProvider = OSGIUtils.getInstance().getService(ClientConfigViewProvider.class);
+        ClientConfigurationView view = viewProvider.createView();
+        ClientConfigurationController controller = new ClientConfigurationController(prefs, view);
+        controller.showDialog();
+    }
+
+    private void switchHistoryMode() {
+        showHistory = !showHistory;
+        doUpdateTreeAsync();
+    }
+
+    private void updateView() {
+        // this is quite an ugly method. there must be a cleaner way to do this
+        Ref ref = view.getSelectedHostOrVm();
+
+        if (ref == null) {
+            SummaryController controller = facadeFactory.getSummary();
+            view.setSubView(controller.getView());
+        } else if (ref instanceof HostRef) {
+            HostRef hostRef = (HostRef) ref;
+            HostInformationController hostController = facadeFactory.getHostController(hostRef);
+            view.setSubView(hostController.getView());
+            view.setStatusBarPrimaryStatus("host: " + hostRef.getHostName() + ", id: " + hostRef.getAgentId());
+        } else if (ref instanceof VmRef) {
+            VmRef vmRef = (VmRef) ref;
+            VmInformationController vmInformation =
+                    vmInfoControllerProvider.getVmInfoController(vmRef);
+            view.setSubView(vmInformation.getView());
+            view.setStatusBarPrimaryStatus("vm: " + vmRef.getName() + ", pid: " + vmRef.getStringID() +
+                                           ", host: " + vmRef.getAgent().getHostName());
+        } else {
+            throw new IllegalArgumentException("unknown type of ref");
+        }
+    }
+
+    private class UpdateListAndTree<T> implements ActionListener<ThermostatExtensionRegistry.Action> {
+
+        private final Class<T> extensionClass;
+        private final CopyOnWriteArrayList<T> extensionList;
+
+        public UpdateListAndTree(Class<T> extensionClass, CopyOnWriteArrayList<T> addRemoveExtensionsFrom) {
+            this.extensionClass = extensionClass;
+            this.extensionList = addRemoveExtensionsFrom;
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public void actionPerformed(ActionEvent<com.redhat.thermostat.common.ThermostatExtensionRegistry.Action> actionEvent) {
+
+            Object payload = actionEvent.getPayload();
+            if (!extensionClass.isInstance(payload)) {
+                throw new IllegalArgumentException("unexpected payload type. expected a " + extensionClass.getName() + " but got " + payload.getClass().getName());
+            }
+
+            T filter = (T) payload;
+
+            switch (actionEvent.getActionId()) {
+            case SERVICE_ADDED:
+                extensionList.add(filter);
+                doUpdateTreeAsync();
+                break;
+
+            case SERVICE_REMOVED:
+                extensionList.remove(filter);
+                doUpdateTreeAsync();
+                break;
+
+            default:
+                logger.log(Level.WARNING, "received unknown event from ExtensionRegistry: " +
+                                           actionEvent.getActionId());
+                break;
+            }
+        }
+    }
+
+    private class VmInformationControllerProvider {
+        private VmInformationController lastSelectedVM;
+        private Map<VmRef, Integer> selectedForVM = new ConcurrentHashMap<>();
+        
+        VmInformationController getVmInfoController(VmRef vmRef) {
+            int id = 0;
+            if (lastSelectedVM != null) {
+                id = lastSelectedVM.getSelectedChildID();
+            }
+            
+            lastSelectedVM = facadeFactory.getVmController(vmRef);
+            if (!lastSelectedVM.selectChildID(id)) {
+                Integer _id = selectedForVM.get(vmRef);
+                id = _id != null? _id : 0;
+                lastSelectedVM.selectChildID(id);
+            }
+
+            selectedForVM.put(vmRef, id);
+            
+            return lastSelectedVM;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/MenuRegistry.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.internal;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+
+import com.redhat.thermostat.client.osgi.service.MenuAction;
+import com.redhat.thermostat.common.ThermostatExtensionRegistry;
+
+public class MenuRegistry extends ThermostatExtensionRegistry<MenuAction> {
+
+    private static final String FILTER = "(" + Constants.OBJECTCLASS + "=" + MenuAction.class.getName() + ")";
+
+    public MenuRegistry(BundleContext context) throws InvalidSyntaxException {
+    	super(context, FILTER, MenuAction.class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/RegistryFactory.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,72 @@
+/*
+ * 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.swing.internal;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+
+class RegistryFactory {
+
+    private BundleContext context;
+    RegistryFactory(BundleContext context) {
+        this.context = context;
+    }
+
+    HostTreeDecoratorRegistry createHostTreeDecoratorRegistry() throws InvalidSyntaxException {
+        return new HostTreeDecoratorRegistry(context);
+    }
+    
+    VMTreeDecoratorRegistry createVMTreeDecoratorRegistry() throws InvalidSyntaxException {
+        return new VMTreeDecoratorRegistry(context);
+    }
+    
+    HostFilterRegistry createHostFilterRegistry() throws InvalidSyntaxException {
+        return new HostFilterRegistry(context);
+    }
+
+    VmFilterRegistry createVmFilterRegistry() throws InvalidSyntaxException {
+        return new VmFilterRegistry(context);
+    }
+    
+    MenuRegistry createMenuRegistry() throws InvalidSyntaxException {
+        return new MenuRegistry(context);
+    }
+    
+    VMInformationRegistry createVMInformationRegistry() throws InvalidSyntaxException {
+        return new VMInformationRegistry(context);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/UiFacadeFactoryImpl.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,199 @@
+/*
+ * 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.swing.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.concurrent.CountDownLatch;
+
+import org.osgi.framework.BundleContext;
+
+import com.redhat.thermostat.client.core.VmInformationService;
+import com.redhat.thermostat.client.core.views.HostInformationViewProvider;
+import com.redhat.thermostat.client.core.views.SummaryViewProvider;
+import com.redhat.thermostat.client.core.views.VmInformationViewProvider;
+import com.redhat.thermostat.client.osgi.service.VMContextAction;
+import com.redhat.thermostat.client.swing.MainWindow;
+import com.redhat.thermostat.client.ui.HostInformationController;
+import com.redhat.thermostat.client.ui.MainWindowController;
+import com.redhat.thermostat.client.ui.SummaryController;
+import com.redhat.thermostat.client.ui.UiFacadeFactory;
+import com.redhat.thermostat.client.ui.VmInformationController;
+import com.redhat.thermostat.common.dao.CpuStatDAO;
+import com.redhat.thermostat.common.dao.HostInfoDAO;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.MemoryStatDAO;
+import com.redhat.thermostat.common.dao.NetworkInterfaceInfoDAO;
+import com.redhat.thermostat.common.dao.VmCpuStatDAO;
+import com.redhat.thermostat.common.dao.VmGcStatDAO;
+import com.redhat.thermostat.common.dao.VmInfoDAO;
+import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+
+public class UiFacadeFactoryImpl implements UiFacadeFactory {
+
+    private CountDownLatch shutdown = new CountDownLatch(1);
+
+    private Collection<VmInformationService> vmInformationServices = new ArrayList<>();
+    private Collection<VMContextAction> contextAction = new ArrayList<>();
+
+    private BundleContext context;
+
+    private HostInfoDAO hostInfoDao;
+    private CpuStatDAO cpuStatDao;
+    private MemoryStatDAO memoryStatDao;
+    private NetworkInterfaceInfoDAO networkInfoDao;
+
+    private VmInfoDAO vmInfoDao;
+    private VmCpuStatDAO vmCpuStatDao;
+    private VmMemoryStatDAO vmMemoryStatDao;
+    private VmGcStatDAO vmGcStatDao;
+
+    private OSGIUtils serviceProvider;
+    
+    UiFacadeFactoryImpl(OSGIUtils serviceProvider, BundleContext context) {
+        this.context = context;
+        this.serviceProvider = serviceProvider;
+    }
+    
+    public UiFacadeFactoryImpl(BundleContext context) {
+        this(OSGIUtils.getInstance(), context);
+    }
+
+    @Override
+    public void setHostInfoDao(HostInfoDAO hostInfoDao) {
+        this.hostInfoDao = hostInfoDao;
+    }
+
+    public void setCpuStatDao(CpuStatDAO cpuStatDao) {
+        this.cpuStatDao = cpuStatDao;
+    }
+
+    public void setMemoryStatDao(MemoryStatDAO memoryStatDao) {
+        this.memoryStatDao = memoryStatDao;
+    }
+
+    public void setNetworkInfoDao(NetworkInterfaceInfoDAO networkInfoDao) {
+        this.networkInfoDao = networkInfoDao;
+    }
+
+    public void setVmInfoDao(VmInfoDAO vmInfoDao) {
+        this.vmInfoDao = vmInfoDao;
+    }
+
+    public void setVmCpuStatDao(VmCpuStatDAO vmCpuStatDao) {
+        this.vmCpuStatDao = vmCpuStatDao;
+    }
+
+    @Override
+    public void setVmMemoryStatDao(VmMemoryStatDAO vmMemoryStatDao) {
+        this.vmMemoryStatDao = vmMemoryStatDao;
+    }
+
+    @Override
+    public void setVmGcStatDao(VmGcStatDAO vmGcStatDao) {
+        this.vmGcStatDao = vmGcStatDao;
+    }
+
+    @Override
+    public MainWindowController getMainWindow() {
+        MainView mainView = new MainWindow();
+        RegistryFactory registryFactory = new RegistryFactory(context);
+        return new MainWindowControllerImpl(this, mainView, registryFactory, hostInfoDao, vmInfoDao);
+    }
+
+    @Override
+    public SummaryController getSummary() {
+        SummaryViewProvider viewProvider = serviceProvider.getService(SummaryViewProvider.class);
+        return new SummaryController(hostInfoDao, vmInfoDao, viewProvider);
+    }
+
+    @Override
+    public HostInformationController getHostController(HostRef ref) {
+        HostInformationViewProvider viewProvider = serviceProvider.getService(HostInformationViewProvider.class);
+        return new HostInformationController(hostInfoDao, networkInfoDao, cpuStatDao, memoryStatDao, ref, viewProvider);
+    }
+
+    @Override
+    public VmInformationController getVmController(VmRef ref) {
+        VmInformationViewProvider viewProvider = serviceProvider.getService(VmInformationViewProvider.class);
+        return new VmInformationController(this, vmInfoDao, vmCpuStatDao, vmMemoryStatDao, vmGcStatDao, ref, viewProvider);
+    }
+
+    @Override
+    public Collection<VmInformationService> getVmInformationServices() {
+        return vmInformationServices;
+    }
+
+    @Override
+    public void addVmInformationService(VmInformationService vmInfoService) {
+        vmInformationServices.add(vmInfoService);
+    }
+
+    @Override
+    public void removeVmInformationService(VmInformationService vmInfoService) {
+        vmInformationServices.remove(vmInfoService);
+    }
+
+    @Override
+    public Collection<VMContextAction> getVMContextActions() {
+        return contextAction;
+    }
+
+    @Override
+    public void addVMContextAction(VMContextAction service) {
+        contextAction.add(service);
+    }
+
+    @Override
+    public void shutdown() {
+        shutdown.countDown();
+    }
+
+    @Override
+    public void shutdown(int exitCode) {
+        // TODO implement returning exit codes
+        shutdown();
+    }
+
+    @Override
+    public void awaitShutdown() throws InterruptedException {
+        shutdown.await();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/VMInformationRegistry.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.internal;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+
+import com.redhat.thermostat.client.core.VmInformationService;
+import com.redhat.thermostat.common.ThermostatExtensionRegistry;
+
+class VMInformationRegistry extends ThermostatExtensionRegistry<VmInformationService> {
+
+    private static final String FILTER = "(&(" + Constants.OBJECTCLASS + "=" + VmInformationService.class.getName() + "))";
+    
+    public VMInformationRegistry(BundleContext context) throws InvalidSyntaxException {
+        super(context, FILTER, VmInformationService.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/VMTreeDecoratorRegistry.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.internal;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+
+import com.redhat.thermostat.client.osgi.service.VmDecorator;
+import com.redhat.thermostat.common.ThermostatExtensionRegistry;
+
+class VMTreeDecoratorRegistry extends ThermostatExtensionRegistry<VmDecorator> {
+
+    private static final String FILTER = "(" + Constants.OBJECTCLASS + "=" + VmDecorator.class.getName() + ")";
+    
+    public VMTreeDecoratorRegistry(BundleContext context) throws InvalidSyntaxException {
+        super(context, FILTER, VmDecorator.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/VmFilterRegistry.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.internal;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+
+import com.redhat.thermostat.client.core.VmFilter;
+import com.redhat.thermostat.common.ThermostatExtensionRegistry;
+
+class VmFilterRegistry extends ThermostatExtensionRegistry<VmFilter> {
+
+    private static final String FILTER = "(" + Constants.OBJECTCLASS + "=" + VmFilter.class.getName() + ")";
+
+    public VmFilterRegistry(BundleContext context) throws InvalidSyntaxException {
+        super(context, FILTER, VmFilter.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/WrapLayout.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2008 Rob Camick, 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.
+ */
+
+/*
+ * Taken from http://tips4java.wordpress.com/2008/11/06/wrap-layout/
+ *
+ * The about page (http://tips4java.wordpress.com/about/) says this:
+ * "You are free to use and/or modify any or all code posted on the Java Tips
+ * Weblog without restriction. A credit in the code comments would be nice,
+ * but not in any way mandatory."
+ */
+
+package com.redhat.thermostat.client.swing.internal;
+
+import java.awt.*;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+
+/**
+ *  FlowLayout subclass that fully supports wrapping of components.
+ */
+public class WrapLayout extends FlowLayout {
+
+    private static final long serialVersionUID = -9169664895883997422L;
+
+    /**
+	* Constructs a new <code>WrapLayout</code> with a left
+	* alignment and a default 5-unit horizontal and vertical gap.
+	*/
+	public WrapLayout()
+	{
+		super();
+	}
+
+	/**
+	* Constructs a new <code>FlowLayout</code> with the specified
+	* alignment and a default 5-unit horizontal and vertical gap.
+	* The value of the alignment argument must be one of
+	* <code>WrapLayout</code>, <code>WrapLayout</code>,
+	* or <code>WrapLayout</code>.
+	* @param align the alignment value
+	*/
+	public WrapLayout(int align)
+	{
+		super(align);
+	}
+
+	/**
+	* Creates a new flow layout manager with the indicated alignment
+	* and the indicated horizontal and vertical gaps.
+	* <p>
+	* The value of the alignment argument must be one of
+	* <code>WrapLayout</code>, <code>WrapLayout</code>,
+	* or <code>WrapLayout</code>.
+	* @param align the alignment value
+	* @param hgap the horizontal gap between components
+	* @param vgap the vertical gap between components
+	*/
+	public WrapLayout(int align, int hgap, int vgap)
+	{
+		super(align, hgap, vgap);
+	}
+
+	/**
+	* Returns the preferred dimensions for this layout given the
+	* <i>visible</i> components in the specified target container.
+	* @param target the component which needs to be laid out
+	* @return the preferred dimensions to lay out the
+	* subcomponents of the specified container
+	*/
+	@Override
+	public Dimension preferredLayoutSize(Container target)
+	{
+		return layoutSize(target, true);
+	}
+
+	/**
+	* Returns the minimum dimensions needed to layout the <i>visible</i>
+	* components contained in the specified target container.
+	* @param target the component which needs to be laid out
+	* @return the minimum dimensions to lay out the
+	* subcomponents of the specified container
+	*/
+	@Override
+	public Dimension minimumLayoutSize(Container target)
+	{
+		Dimension minimum = layoutSize(target, false);
+		minimum.width -= (getHgap() + 1);
+		return minimum;
+	}
+
+	/**
+	* Returns the minimum or preferred dimension needed to layout the target
+	* container.
+	*
+	* @param target target to get layout size for
+	* @param preferred should preferred size be calculated
+	* @return the dimension to layout the target container
+	*/
+	private Dimension layoutSize(Container target, boolean preferred)
+	{
+	synchronized (target.getTreeLock())
+	{
+		//  Each row must fit with the width allocated to the containter.
+		//  When the container width = 0, the preferred width of the container
+		//  has not yet been calculated so lets ask for the maximum.
+
+		int targetWidth = target.getSize().width;
+
+		if (targetWidth == 0)
+			targetWidth = Integer.MAX_VALUE;
+
+		int hgap = getHgap();
+		int vgap = getVgap();
+		Insets insets = target.getInsets();
+		int horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2);
+		int maxWidth = targetWidth - horizontalInsetsAndGap;
+
+		//  Fit components into the allowed width
+
+		Dimension dim = new Dimension(0, 0);
+		int rowWidth = 0;
+		int rowHeight = 0;
+
+		int nmembers = target.getComponentCount();
+
+		for (int i = 0; i < nmembers; i++)
+		{
+			Component m = target.getComponent(i);
+
+			if (m.isVisible())
+			{
+				Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize();
+
+				//  Can't add the component to current row. Start a new row.
+
+				if (rowWidth + d.width > maxWidth)
+				{
+					addRow(dim, rowWidth, rowHeight);
+					rowWidth = 0;
+					rowHeight = 0;
+				}
+
+				//  Add a horizontal gap for all components after the first
+
+				if (rowWidth != 0)
+				{
+					rowWidth += hgap;
+				}
+
+				rowWidth += d.width;
+				rowHeight = Math.max(rowHeight, d.height);
+			}
+		}
+
+		addRow(dim, rowWidth, rowHeight);
+
+		dim.width += horizontalInsetsAndGap;
+		dim.height += insets.top + insets.bottom + vgap * 2;
+
+		//	When using a scroll pane or the DecoratedLookAndFeel we need to
+		//  make sure the preferred size is less than the size of the
+		//  target containter so shrinking the container size works
+		//  correctly. Removing the horizontal gap is an easy way to do this.
+
+		Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target);
+
+		if (scrollPane != null)
+		{
+			dim.width -= (hgap + 1);
+		}
+
+		return dim;
+	}
+	}
+
+	/*
+	 *  A new row has been completed. Use the dimensions of this row
+	 *  to update the preferred size for the container.
+	 *
+	 *  @param dim update the width and height when appropriate
+	 *  @param rowWidth the width of the row to add
+	 *  @param rowHeight the height of the row to add
+	 */
+	private void addRow(Dimension dim, int rowWidth, int rowHeight)
+	{
+		dim.width = Math.max(dim.width, rowWidth);
+
+		if (dim.height > 0)
+		{
+			dim.height += getVgap();
+		}
+
+		dim.height += rowHeight;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/components/DecoratedDefaultMutableTreeNode.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.swing.internal.components;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+
+import com.redhat.thermostat.client.ui.Decorator;
+import com.redhat.thermostat.common.dao.Ref;
+
+public class DecoratedDefaultMutableTreeNode  extends DefaultMutableTreeNode {
+    
+    private List<Decorator> decorators;
+    
+    public DecoratedDefaultMutableTreeNode(Ref ref) {
+        super(ref);
+        decorators = new ArrayList<>();
+    }
+    
+    public void addDecorator(Decorator decorator) {
+        decorators.add(decorator);
+    }
+    
+    public void setDecorators(List<Decorator> decorators) {
+        this.decorators = decorators;
+    }
+    
+    public List<Decorator> getDecorators() {
+        return decorators;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/config/ConnectionConfiguration.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.internal.config;
+
+import com.redhat.thermostat.common.cli.AuthenticationConfiguration;
+import com.redhat.thermostat.common.config.ClientPreferences;
+import com.redhat.thermostat.common.config.StartupConfiguration;
+
+public class ConnectionConfiguration implements StartupConfiguration, AuthenticationConfiguration {
+
+    private final ClientPreferences clientPrefs;
+
+    public ConnectionConfiguration(ClientPreferences clientPrefs) {
+        this.clientPrefs = clientPrefs;
+    }
+
+    @Override
+    public String getDBConnectionString() {
+        return clientPrefs.getConnectionUrl();
+    }
+    
+    @Override
+    public String getPassword() {
+        return clientPrefs.getPassword();
+    }
+    
+    @Override
+    public String getUsername() {
+        return clientPrefs.getUserName();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/ApplicationServiceProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,64 @@
+/*
+ * 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.swing.internal.osgi;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import com.redhat.thermostat.client.osgi.service.ApplicationCache;
+import com.redhat.thermostat.client.osgi.service.ApplicationService;
+
+public class ApplicationServiceProvider implements ApplicationService {
+
+    private ApplicationCache cache = new ApplicationCache();
+
+    // NOTE: When merging with ApplicationContext, this could be provided by the same
+    // thread pool that does the timer scheduling. Not sure we want this though,
+    // as scheduled thread pools are always limited in number of threads (could lead to deadlocks
+    // when used carelessly).
+    private ExecutorService executor = Executors.newCachedThreadPool();
+
+    @Override
+    public ApplicationCache getApplicationCache() {
+        return cache;
+    }
+
+    @Override
+    public ExecutorService getApplicationExecutor() {
+        return executor;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/ContextActionServiceProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,52 @@
+/*
+ * 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.swing.internal.osgi;
+
+import com.redhat.thermostat.client.osgi.service.ContextAction;
+
+public class ContextActionServiceProvider implements ContextAction {
+  
+    @Override
+    public String getName() {
+        return "system context";
+    }
+
+    @Override
+    public String getDescription() {
+        return "system context";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/ThermostatActivator.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.internal.osgi;
+
+import java.util.Arrays;
+
+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.client.core.views.AgentInformationViewProvider;
+import com.redhat.thermostat.client.core.views.ClientConfigViewProvider;
+import com.redhat.thermostat.client.core.views.HostCpuViewProvider;
+import com.redhat.thermostat.client.core.views.HostInformationViewProvider;
+import com.redhat.thermostat.client.core.views.HostMemoryViewProvider;
+import com.redhat.thermostat.client.core.views.HostOverviewViewProvider;
+import com.redhat.thermostat.client.core.views.SummaryViewProvider;
+import com.redhat.thermostat.client.core.views.VmCpuViewProvider;
+import com.redhat.thermostat.client.core.views.VmGcViewProvider;
+import com.redhat.thermostat.client.core.views.VmInformationViewProvider;
+import com.redhat.thermostat.client.core.views.VmOverviewViewProvider;
+import com.redhat.thermostat.client.osgi.service.HostDecorator;
+import com.redhat.thermostat.client.swing.internal.GUIClientCommand;
+import com.redhat.thermostat.client.swing.internal.HostIconDecorator;
+import com.redhat.thermostat.client.swing.internal.Main;
+import com.redhat.thermostat.client.swing.internal.UiFacadeFactoryImpl;
+import com.redhat.thermostat.client.swing.views.SwingAgentInformationViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingClientConfigurationViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingHostCpuViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingHostInformationViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingHostMemoryViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingHostOverviewViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingSummaryViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingVmCpuViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingVmGcViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingVmInformationViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingVmOverviewViewProvider;
+import com.redhat.thermostat.client.ui.UiFacadeFactory;
+import com.redhat.thermostat.common.cli.CommandRegistry;
+import com.redhat.thermostat.common.cli.CommandRegistryImpl;
+import com.redhat.thermostat.utils.keyring.Keyring;
+
+public class ThermostatActivator implements BundleActivator {
+
+    private VmInformationServiceTracker vmInfoServiceTracker;
+    private VMContextActionServiceTracker contextActionTracker;
+
+    private CommandRegistry cmdReg;
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Override
+    public void start(final BundleContext context) throws Exception {
+        
+        HostDecorator hostDecorator = new HostIconDecorator();
+        context.registerService(HostDecorator.class.getName(), hostDecorator, null);
+        
+        // Host views
+        HostInformationViewProvider infoProvider = new SwingHostInformationViewProvider();
+        context.registerService(HostInformationViewProvider.class.getName(), infoProvider, null);
+        HostCpuViewProvider cpuProvider = new SwingHostCpuViewProvider();
+        context.registerService(HostCpuViewProvider.class.getName(), cpuProvider, null);
+        HostOverviewViewProvider provider = new SwingHostOverviewViewProvider();
+        context.registerService(HostOverviewViewProvider.class.getName(), provider, null);
+        HostMemoryViewProvider memoryProvider = new SwingHostMemoryViewProvider();
+        context.registerService(HostMemoryViewProvider.class.getName(), memoryProvider, null);
+        
+        // Vm views
+        VmInformationViewProvider vmInfoProvider = new SwingVmInformationViewProvider();
+        context.registerService(VmInformationViewProvider.class.getName(), vmInfoProvider, null);
+        VmOverviewViewProvider vmOverviewProvider = new SwingVmOverviewViewProvider();
+        context.registerService(VmOverviewViewProvider.class.getName(), vmOverviewProvider, null);
+        VmGcViewProvider vmGcProvider = new SwingVmGcViewProvider();
+        context.registerService(VmGcViewProvider.class.getName(), vmGcProvider, null);
+        VmCpuViewProvider vmCpuProvider = new SwingVmCpuViewProvider();
+        context.registerService(VmCpuViewProvider.class.getName(), vmCpuProvider, null);
+        
+        // Summary view
+        SummaryViewProvider summaryViewProvider = new SwingSummaryViewProvider();
+        context.registerService(SummaryViewProvider.class.getName(), summaryViewProvider, null);
+
+        // AgentInformation and ClientConfiguraiton view
+        AgentInformationViewProvider agentViewProvider = new SwingAgentInformationViewProvider();
+        context.registerService(AgentInformationViewProvider.class.getName(), agentViewProvider, null);
+        ClientConfigViewProvider clientConfigViewProvider = new SwingClientConfigurationViewProvider();
+        context.registerService(ClientConfigViewProvider.class, clientConfigViewProvider, null);
+        
+        ServiceTracker tracker = new ServiceTracker(context, Keyring.class.getName(), null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+              
+                Keyring keyring = (Keyring) context.getService(reference);
+                
+                UiFacadeFactory uiFacadeFactory = new UiFacadeFactoryImpl(context);
+
+                vmInfoServiceTracker = new VmInformationServiceTracker(context, uiFacadeFactory);
+                vmInfoServiceTracker.open();
+                contextActionTracker = new VMContextActionServiceTracker(context, uiFacadeFactory);
+                contextActionTracker.open();
+
+                cmdReg = new CommandRegistryImpl(context);
+                Main main = new Main(keyring, uiFacadeFactory, new String[0]);
+                
+                GUIClientCommand cmd = new GUIClientCommand(main);
+                cmd.setBundleContext(context);
+                cmdReg.registerCommands(Arrays.asList(cmd));
+                
+                return super.addingService(reference);
+            }
+        };
+        tracker.open();
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        vmInfoServiceTracker.close(); //context.removeServiceListener(vmInfoServiceTracker);
+        contextActionTracker.close();
+        cmdReg.unregisterCommands();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/VMContextActionServiceTracker.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.swing.internal.osgi;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+import com.redhat.thermostat.client.osgi.service.VMContextAction;
+import com.redhat.thermostat.client.ui.UiFacadeFactory;
+
+@SuppressWarnings("rawtypes")
+class VMContextActionServiceTracker extends ServiceTracker {
+
+    private UiFacadeFactory uiFacadeFactory;
+
+    private BundleContext context;
+
+    @SuppressWarnings("unchecked")
+    VMContextActionServiceTracker(BundleContext context, UiFacadeFactory uiFacadeFactory) {
+        super(context, VMContextAction.class.getName(), null);
+        this.context = context;
+        this.uiFacadeFactory = uiFacadeFactory;
+    }
+
+    @Override
+    public Object addingService(ServiceReference reference) {
+        @SuppressWarnings("unchecked")
+        VMContextAction service = (VMContextAction) context.getService(reference);
+        uiFacadeFactory.addVMContextAction(service);
+        return service;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/VmInformationServiceTracker.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,70 @@
+/*
+ * 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.swing.internal.osgi;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+import com.redhat.thermostat.client.core.VmInformationService;
+import com.redhat.thermostat.client.ui.UiFacadeFactory;
+
+class VmInformationServiceTracker extends ServiceTracker {
+
+    private UiFacadeFactory uiFacadeFactory;
+
+    private BundleContext context;
+
+    VmInformationServiceTracker(BundleContext context, UiFacadeFactory uiFacadeFactory) {
+        super(context, VmInformationService.class.getName(), null);
+        this.context = context;
+        this.uiFacadeFactory = uiFacadeFactory;
+    }
+
+    @Override
+    public Object addingService(ServiceReference reference) {
+        VmInformationService service = (VmInformationService) super.addingService(reference);
+        uiFacadeFactory.addVmInformationService(service);
+        return service;
+    }
+
+    @Override
+    public void removedService(ServiceReference reference, Object service) {
+        uiFacadeFactory.removeVmInformationService((VmInformationService)service);
+        super.removedService(reference, service);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/AgentInformationDisplayFrame.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,465 @@
+/*
+ * 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.swing.views;
+
+import java.awt.BorderLayout;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.swing.DefaultListModel;
+import javax.swing.GroupLayout;
+import javax.swing.GroupLayout.Alignment;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTable;
+import javax.swing.LayoutStyle.ComponentPlacement;
+import javax.swing.ListSelectionModel;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.DefaultTableModel;
+
+import com.redhat.thermostat.client.core.views.AgentInformationDisplayView;
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.swing.components.LabelField;
+import com.redhat.thermostat.client.swing.components.SectionHeader;
+import com.redhat.thermostat.client.swing.components.ValueField;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.locale.Translate;
+
+public class AgentInformationDisplayFrame extends AgentInformationDisplayView {
+
+    private static final Translate<LocaleResources> translate = LocaleResources.createLocalizer();
+
+    private static final String[] BACKEND_TABLE_COLUMN_NAMES = new String[] {
+        translate.localize(LocaleResources.AGENT_INFO_BACKEND_NAME_COLUMN),
+        translate.localize(LocaleResources.AGENT_INFO_BACKEND_STATUS_COLUMN),
+    };
+
+    private final CopyOnWriteArrayList<ActionListener<ConfigurationAction>> listeners = new CopyOnWriteArrayList<>();
+
+    private final JFrame frame;
+
+    private final ConfigurationCompleteListener configurationComplete;
+    private final AgentChangedListener agentChanged;
+    private final WindowClosingListener windowListener;
+
+    private final JButton closeButton;
+
+    private final JList<String> agentList;
+    private final DefaultListModel<String> listModel;
+
+    private final ValueField currentAgentName;
+    private final ValueField currentAgentId;
+    private final ValueField currentAgentCommandAddress;
+    private final ValueField currentAgentStartTime;
+    private final ValueField currentAgentStopTime;
+
+    private final JTable backendsTable;
+    private final DefaultTableModel backendsTableModel;
+    private final ValueField backendDescription;
+
+    public AgentInformationDisplayFrame() {
+        assertInEDT();
+
+        configurationComplete = new ConfigurationCompleteListener();
+        agentChanged = new AgentChangedListener();
+        windowListener = new WindowClosingListener();
+
+        frame = new JFrame();
+        frame.setTitle(translate.localize(LocaleResources.AGENT_INFO_WINDOW_TITLE));
+        frame.addWindowListener(windowListener);
+
+        closeButton = new JButton(translate.localize(LocaleResources.BUTTON_CLOSE));
+        closeButton.addActionListener(configurationComplete);
+        closeButton.setName("close");
+
+        JSplitPane splitPane = new JSplitPane();
+        splitPane.setResizeWeight(0.35);
+
+        GroupLayout mainLayout = new GroupLayout(frame.getContentPane());
+        mainLayout.setHorizontalGroup(
+            mainLayout.createParallelGroup(Alignment.TRAILING)
+                .addGroup(mainLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addGroup(mainLayout.createParallelGroup(Alignment.TRAILING)
+                        .addComponent(splitPane, GroupLayout.DEFAULT_SIZE, 664, Short.MAX_VALUE)
+                        .addComponent(closeButton))
+                    .addContainerGap()));
+
+        mainLayout.setVerticalGroup(
+            mainLayout.createParallelGroup(Alignment.TRAILING)
+                .addGroup(mainLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addComponent(splitPane, GroupLayout.DEFAULT_SIZE, 472, Short.MAX_VALUE)
+                    .addPreferredGap(ComponentPlacement.UNRELATED)
+                    .addComponent(closeButton)
+                    .addContainerGap()));
+
+        JPanel agentListPanel = new JPanel();
+        splitPane.setLeftComponent(agentListPanel);
+
+        JLabel agentLabel = new JLabel(translate.localize(LocaleResources.AGENT_INFO_AGENTS_LIST));
+
+        JScrollPane scrollPane = new JScrollPane();
+
+        listModel = new DefaultListModel<String>();
+        agentList = new JList<String>(listModel);
+        agentList.setName("agentList");
+        agentList.addListSelectionListener(agentChanged);
+        agentListPanel.setLayout(new BorderLayout());
+
+        scrollPane.setViewportView(agentList);
+        agentListPanel.add(scrollPane);
+        agentListPanel.add(agentLabel, BorderLayout.NORTH);
+
+        JPanel agentConfigurationPanel = new JPanel();
+        splitPane.setRightComponent(agentConfigurationPanel);
+
+        SectionHeader agentSectionTitle = new SectionHeader(translate.localize(LocaleResources.AGENT_INFO_AGENT_SECTION_TITLE));
+
+        LabelField agentNameLabel = new LabelField(translate.localize(LocaleResources.AGENT_INFO_AGENT_NAME_LABEL));
+        LabelField agentIdLabel = new LabelField(translate.localize(LocaleResources.AGENT_INFO_AGENT_ID_LABEL));
+        LabelField agentConfigurationAddressLabel = new LabelField(translate.localize(LocaleResources.AGENT_INFO_AGENT_COMMAND_ADDRESS_LABEL));
+        LabelField agentStartTimeLabel = new LabelField(translate.localize(LocaleResources.AGENT_INFO_AGENT_START_TIME_LABEL));
+        LabelField agentStopTimeLabel = new LabelField(translate.localize(LocaleResources.AGENT_INFO_AGENT_STOP_TIME_LABEL));
+
+        String notAvailable = translate.localize(LocaleResources.INFORMATION_NOT_AVAILABLE);
+
+        currentAgentName = new ValueField(notAvailable);
+        currentAgentName.setName("agentName");
+        currentAgentId = new ValueField(notAvailable);
+        currentAgentId.setName("agentId");
+        currentAgentCommandAddress = new ValueField(notAvailable);
+        currentAgentCommandAddress.setName("commandAddress");
+        currentAgentStartTime = new ValueField(notAvailable);
+        currentAgentStartTime.setName("startTime");
+        currentAgentStopTime = new ValueField(notAvailable);
+        currentAgentStopTime.setName("stopTime");
+
+        SectionHeader backendSectionTitle = new SectionHeader(translate.localize(LocaleResources.AGENT_INFO_BACKENDS_SECTION_TITLE));
+
+        backendsTableModel = new DefaultTableModel();
+        backendsTableModel.setColumnIdentifiers(BACKEND_TABLE_COLUMN_NAMES);
+
+        backendsTable = new JTable(backendsTableModel);
+        backendsTable.setName("backends");
+        backendsTable.setCellSelectionEnabled(false);
+        backendsTable.setColumnSelectionAllowed(false);
+        backendsTable.setRowSelectionAllowed(true);
+        backendsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        backendsTable.getSelectionModel().addListSelectionListener(new BackendSelectionListener());
+
+        JScrollPane backendsTableScollPane = new JScrollPane(backendsTable);
+
+        JLabel backendDescriptionLabel = new JLabel(translate.localize(LocaleResources.AGENT_INFO_BACKEND_DESCRIPTION_LABEL));
+        backendDescription = new ValueField(notAvailable);
+        backendDescription.setName("backendDescription");
+
+        GroupLayout agentConfigurationPanelLayout = new GroupLayout(agentConfigurationPanel);
+        agentConfigurationPanelLayout.setHorizontalGroup(
+            agentConfigurationPanelLayout.createParallelGroup()
+                .addComponent(agentSectionTitle, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addGroup(agentConfigurationPanelLayout.createSequentialGroup()
+                    .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.LEADING, true)
+                        .addComponent(agentNameLabel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                        .addComponent(agentIdLabel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                        .addComponent(agentConfigurationAddressLabel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                        .addComponent(agentStartTimeLabel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                        .addComponent(agentStopTimeLabel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                    .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.LEADING, true)
+                        .addComponent(currentAgentName, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
+                        .addComponent(currentAgentId, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
+                        .addComponent(currentAgentCommandAddress, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
+                        .addComponent(currentAgentStartTime, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
+                        .addComponent(currentAgentStopTime, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)))
+                .addComponent(backendSectionTitle, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
+                .addComponent(backendsTableScollPane, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
+                .addComponent(backendDescriptionLabel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addComponent(backendDescription, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE));
+
+        agentConfigurationPanelLayout.setVerticalGroup(
+            agentConfigurationPanelLayout.createSequentialGroup()
+                .addComponent(agentSectionTitle)
+                .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.BASELINE, false)
+                    .addComponent(agentNameLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                    .addComponent(currentAgentName, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.BASELINE, false)
+                    .addComponent(agentIdLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                    .addComponent(currentAgentId, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.BASELINE, false)
+                    .addComponent(agentConfigurationAddressLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                    .addComponent(currentAgentCommandAddress, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.BASELINE, false)
+                    .addComponent(agentStartTimeLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                    .addComponent(currentAgentStartTime, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                .addGroup(agentConfigurationPanelLayout.createParallelGroup(Alignment.BASELINE, false)
+                    .addComponent(agentStopTimeLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                    .addComponent(currentAgentStopTime, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                .addComponent(backendSectionTitle)
+                .addComponent(backendsTableScollPane)
+                .addComponent(backendDescriptionLabel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE)
+                .addComponent(backendDescription, 30, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE));
+
+        agentConfigurationPanelLayout.setAutoCreateGaps(true);
+        agentConfigurationPanelLayout.setAutoCreateContainerGaps(true);
+        agentConfigurationPanel.setLayout(agentConfigurationPanelLayout);
+
+        frame.getContentPane().setLayout(mainLayout);
+
+    }
+
+    @Override
+    public void addConfigurationListener(ActionListener<ConfigurationAction> listener) {
+        listeners.add(listener);
+    }
+
+    @Override
+    public void removeConfigurationListener(ActionListener<ConfigurationAction> listener) {
+        listeners.remove(listener);
+    }
+
+    @Override
+    public void addAgent(final String agentName) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                listModel.addElement(agentName);
+                if (agentList.getSelectedIndex() == -1) {
+                    agentList.setSelectedIndex(0);
+                }
+            }
+        });
+    }
+
+    @Override
+    public String getSelectedAgent() {
+        assertInEDT();
+        return agentList.getSelectedValue();
+    }
+
+    @Override
+    public void clearAllAgents() {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                listModel.clear();
+            }
+        });
+    }
+
+    @Override
+    public void setSelectedAgentName(final String agentName) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                currentAgentName.setText(agentName);
+            }
+        });
+    }
+
+    @Override
+    public void setSelectedAgentId(final String agentId) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                currentAgentId.setText(agentId);
+            }
+        });
+    }
+
+    @Override
+    public void setSelectedAgentCommandAddress(final String address) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                currentAgentCommandAddress.setText(address);
+            }
+        });
+    }
+
+    @Override
+    public void setSelectedAgentStartTime(final String startTime) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                currentAgentStartTime.setText(startTime);
+            }
+        });
+    }
+
+    @Override
+    public void setSelectedAgentStopTime(final String stopTime) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                currentAgentStopTime.setText(stopTime);
+            }
+        });
+    }
+
+    @Override
+    public void setSelectedAgentBackendStatus(final Map<String, String> backendStatus) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                int i = 0;
+                for (Entry<String, String> entry : backendStatus.entrySet()) {
+                    String backendName = entry.getKey();
+                    String status = entry.getValue();
+                    int rowCount = backendsTableModel.getRowCount();
+                    if (i >= rowCount) {
+                        Object[] rowData = new String[] { backendName, status };
+                        backendsTableModel.insertRow(i, rowData);
+                    } else {
+                        backendsTableModel.setValueAt(backendName, i, 0);
+                        backendsTableModel.setValueAt(status, i, 1);
+                    }
+                    i++;
+                }
+
+                if (backendsTable.getRowCount() > 0 && backendsTable.getSelectedRow() == -1) {
+                    backendsTable.setRowSelectionInterval(0, 0);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void setSelectedAgentBackendDescription(final String description) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                backendDescription.setText(description);
+            }
+        });
+    }
+
+    @Override
+    public void showDialog() {
+        assertInEDT();
+
+        frame.pack();
+        frame.setVisible(true);
+
+        agentList.setSelectedIndex(0);
+    }
+
+    @Override
+    public void hideDialog() {
+        assertInEDT();
+
+        frame.setVisible(false);
+        frame.dispose();
+    }
+
+    /** This is for tests only */
+    JFrame getFrame() {
+        return frame;
+    }
+
+    private void fireAction(ActionEvent<ConfigurationAction> actionEvent) {
+        for (ActionListener<ConfigurationAction> l : listeners) {
+            l.actionPerformed(actionEvent);
+        }
+    }
+
+    private static void assertInEDT() {
+        if (!SwingUtilities.isEventDispatchThread()) {
+            throw new IllegalStateException("must be called from within the swing EDT");
+        }
+    }
+
+    private class ConfigurationCompleteListener implements java.awt.event.ActionListener {
+        @Override
+        public void actionPerformed(java.awt.event.ActionEvent e) {
+            Object source = e.getSource();
+            if (source == closeButton) {
+                fireAction(new ActionEvent<>(AgentInformationDisplayFrame.this, ConfigurationAction.CLOSE));
+            }
+        }
+    }
+
+    private class WindowClosingListener extends WindowAdapter {
+        @Override
+        public void windowClosing(WindowEvent e) {
+            fireAction(new ActionEvent<>(AgentInformationDisplayFrame.this, ConfigurationAction.CLOSE));
+        }
+    }
+
+    private class AgentChangedListener implements ListSelectionListener {
+        @Override
+        public void valueChanged(ListSelectionEvent e) {
+            if (e.getSource() == agentList) {
+                if (e.getValueIsAdjusting()) {
+                    return;
+                }
+                fireAction(new ActionEvent<>(AgentInformationDisplayFrame.this, ConfigurationAction.SWITCH_AGENT));
+            } else {
+                throw new IllegalStateException("unknown trigger");
+            }
+        }
+    }
+
+    private class BackendSelectionListener implements ListSelectionListener {
+
+        @Override
+        public void valueChanged(ListSelectionEvent e) {
+            if (e.getValueIsAdjusting()) {
+                return;
+            }
+
+            int rowIndex = e.getFirstIndex();
+            String backendName = (String) backendsTableModel.getValueAt(rowIndex, 0);
+            ActionEvent<ConfigurationAction> event = new ActionEvent<>(AgentInformationDisplayFrame.this,
+                    ConfigurationAction.SHOW_BACKEND_DESCRIPTION);
+            event.setPayload(backendName);
+            fireAction(event);
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/ClientConfigurationPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.views;
+
+import javax.swing.GroupLayout;
+import javax.swing.GroupLayout.Alignment;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JTextField;
+import javax.swing.LayoutStyle.ComponentPlacement;
+import javax.swing.border.TitledBorder;
+
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.common.locale.Translate;
+
+@SuppressWarnings("serial")
+class ClientConfigurationPanel extends JPanel {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    final JTextField storageUrl = new JTextField();
+    final JTextField userName = new JTextField();
+    final JPasswordField password = new JPasswordField();
+    
+    final JCheckBox saveEntitlements;
+    
+    public ClientConfigurationPanel() {
+        setBorder(new TitledBorder(null,
+                  translator.localize(LocaleResources.CLIENT_PREFS_CONNECTION),
+                  TitledBorder.LEFT, TitledBorder.TOP, null, null));
+
+        JLabel storageURLText = new JLabel(translator.localize(LocaleResources.CLIENT_PREFS_STORAGE_URL));
+        storageURLText.setName("");
+        
+        storageUrl.setColumns(10);
+        storageUrl.setName("connectionUrl");
+        
+        JLabel userNameText = new JLabel(translator.localize(LocaleResources.CLIENT_PREFS_STORAGE_USERNAME));
+        userNameText.setName("userNameText");
+        
+        userName.setName("username");
+        userName.setColumns(10);
+        
+        JLabel passowrdText = new JLabel("Password");
+        passowrdText.setName("passwordText");
+        
+        password.setName("password");
+        password.setColumns(10);
+        
+        saveEntitlements = new JCheckBox(translator.localize(LocaleResources.CLIENT_PREFS_STORAGE_SAVE_ENTITLEMENTS));
+        saveEntitlements.setName("saveEntitlements");
+        saveEntitlements.setSelected(false);
+
+        GroupLayout groupLayout = new GroupLayout(this);
+        groupLayout.setHorizontalGroup(
+            groupLayout.createParallelGroup(Alignment.TRAILING)
+                .addGroup(groupLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
+                        .addComponent(saveEntitlements)
+                        .addGroup(groupLayout.createSequentialGroup()
+                            .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
+                                .addComponent(storageURLText, GroupLayout.PREFERRED_SIZE, 83, GroupLayout.PREFERRED_SIZE)
+                                .addGroup(groupLayout.createParallelGroup(Alignment.LEADING, false)
+                                    .addComponent(passowrdText, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                                    .addComponent(userNameText, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
+                            .addPreferredGap(ComponentPlacement.UNRELATED)
+                            .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
+                                .addComponent(userName, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 326, Short.MAX_VALUE)
+                                .addComponent(storageUrl, GroupLayout.DEFAULT_SIZE, 326, Short.MAX_VALUE)
+                                .addComponent(password, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 326, Short.MAX_VALUE))))
+                    .addGap(24))
+        );
+        groupLayout.setVerticalGroup(
+            groupLayout.createParallelGroup(Alignment.LEADING)
+                .addGroup(groupLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
+                        .addComponent(storageURLText)
+                        .addComponent(storageUrl, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
+                        .addGroup(groupLayout.createSequentialGroup()
+                            .addGap(8)
+                            .addComponent(userNameText))
+                        .addGroup(groupLayout.createSequentialGroup()
+                            .addPreferredGap(ComponentPlacement.RELATED)
+                            .addComponent(userName, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)))
+                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
+                        .addGroup(groupLayout.createSequentialGroup()
+                            .addGap(8)
+                            .addComponent(passowrdText))
+                        .addGroup(groupLayout.createSequentialGroup()
+                            .addPreferredGap(ComponentPlacement.RELATED)
+                            .addComponent(password, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)))
+                    .addPreferredGap(ComponentPlacement.UNRELATED)
+                    .addComponent(saveEntitlements)
+                    .addContainerGap(15, Short.MAX_VALUE))
+        );
+        setLayout(groupLayout);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/ClientConfigurationSwing.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,263 @@
+/*
+ * 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.swing.views;
+
+import java.awt.Frame;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
+import javax.swing.WindowConstants;
+
+import com.redhat.thermostat.client.core.views.ClientConfigurationView;
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.swing.components.EdtHelper;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.locale.Translate;
+
+public class ClientConfigurationSwing implements ClientConfigurationView {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private final WindowClosingListener windowClosingListener;
+
+    private final ClientConfigurationPanel configurationPanel;
+
+    private final CopyOnWriteArrayList<ActionListener<Action>> listeners = new CopyOnWriteArrayList<>();
+
+    private JDialog dialog;
+
+    public ClientConfigurationSwing() {
+        assertInEDT();
+
+        windowClosingListener = new WindowClosingListener();
+        configurationPanel = new ClientConfigurationPanel();
+        
+        final JOptionPane optionPane = new JOptionPane(configurationPanel);
+        optionPane.setOptionType(JOptionPane.OK_CANCEL_OPTION);
+        optionPane.addPropertyChangeListener(new PropertyChangeListener() {
+            @Override
+            public void propertyChange(PropertyChangeEvent evt) {
+                String propertyName = evt.getPropertyName();
+                if ((evt.getSource() == optionPane) &&
+                    (propertyName.equals(JOptionPane.VALUE_PROPERTY))) {
+                    if (dialog.isVisible()) {
+                        if (evt.getNewValue().equals(JOptionPane.OK_OPTION)) {
+                            fireAction(new ActionEvent<>(ClientConfigurationSwing.this, Action.CLOSE_ACCEPT));
+                        } else if (evt.getNewValue().equals(JOptionPane.CANCEL_OPTION)) {
+                            fireAction(new ActionEvent<>(ClientConfigurationSwing.this, Action.CLOSE_CANCEL));
+                        }
+                    }
+                }
+            }
+        });
+
+        dialog = new JDialog((Frame) null, translator.localize(LocaleResources.CLIENT_PREFS_WINDOW_TITLE));
+        dialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+        dialog.setContentPane(optionPane);
+        dialog.addWindowListener(windowClosingListener);
+    }
+
+    JDialog getDialog() {
+        return dialog;
+    }
+
+    @Override
+    public void showDialog() {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                dialog.pack();
+                dialog.setVisible(true);
+            }
+        });
+    }
+
+    @Override
+    public void hideDialog() {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                dialog.setVisible(false);
+                dialog.dispose();
+                dialog = null;
+            }
+
+        });
+    }
+
+    @Override
+    public String getConnectionUrl() {
+        try {
+            return new EdtHelper().callAndWait(new Callable<String>() {
+                @Override
+                public String call() throws Exception {
+                    return configurationPanel.storageUrl.getText();
+                }
+            });
+        } catch (InvocationTargetException | InterruptedException e) {
+            InternalError error = new InternalError();
+            error.initCause(e);
+            throw error;
+        }
+    }
+
+    @Override
+    public void setConnectionUrl(final String url) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                configurationPanel.storageUrl.setText(url);
+            }
+        });
+    }
+
+    @Override
+    public void addListener(ActionListener<Action> listener) {
+        listeners.add(listener);
+    }
+
+    @Override
+    public void removeListener(ActionListener<Action> listener) {
+        listeners.remove(listener);
+    }
+
+    private void fireAction(ActionEvent<Action> actionEvent) {
+        for (ActionListener<Action> listener: listeners) {
+            listener.actionPerformed(actionEvent);
+        }
+    }
+
+    private void assertInEDT() {
+        if (!SwingUtilities.isEventDispatchThread()) {
+            throw new IllegalStateException("must be invoked in the EDT");
+        }
+    }
+
+    class WindowClosingListener extends WindowAdapter {
+        @Override
+        public void windowClosing(WindowEvent e) {
+            fireAction(new ActionEvent<>(ClientConfigurationSwing.this, Action.CLOSE_CANCEL));
+        }
+    }
+
+    @Override
+    public void setPassword(final String password) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                configurationPanel.password.setText(password);
+            }
+        });
+    }
+    
+    @Override
+    public void setUserName(final String username) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                configurationPanel.userName.setText(username);
+            }
+        });
+    };
+    
+    @Override
+    public String getPassword() {
+        try {
+            return new EdtHelper().callAndWait(new Callable<String>() {
+                @Override
+                public String call() throws Exception {
+                    return configurationPanel.password.getText();
+                }
+            });
+        } catch (InvocationTargetException | InterruptedException e) {
+            InternalError error = new InternalError();
+            error.initCause(e);
+            throw error;
+        }
+    }
+    
+    @Override
+    public String getUserName() {
+        try {
+            return new EdtHelper().callAndWait(new Callable<String>() {
+                @Override
+                public String call() throws Exception {
+                    return configurationPanel.userName.getText();
+                }
+            });
+        } catch (InvocationTargetException | InterruptedException e) {
+            InternalError error = new InternalError();
+            error.initCause(e);
+            throw error;
+        }
+    }
+    
+    @Override
+    public boolean getSaveEntitlements() {
+        try {
+            return new EdtHelper().callAndWait(new Callable<Boolean>() {
+                @Override
+                public Boolean call() throws Exception {
+                    return configurationPanel.saveEntitlements.isSelected();
+                }
+            });
+        } catch (InvocationTargetException | InterruptedException e) {
+            InternalError error = new InternalError();
+            error.initCause(e);
+            throw error;
+        }
+    }
+    
+    @Override
+    public void setSaveEntitlemens(final boolean save) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                configurationPanel.saveEntitlements.setSelected(save);
+            }
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/HostCpuPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,297 @@
+/*
+ * 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.swing.views;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.GroupLayout;
+import javax.swing.GroupLayout.Alignment;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.LayoutStyle.ComponentPlacement;
+import javax.swing.SwingUtilities;
+import javax.swing.text.JTextComponent;
+
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.renderer.xy.XYItemRenderer;
+import org.jfree.data.time.FixedMillisecond;
+import org.jfree.data.time.RegularTimePeriod;
+import org.jfree.data.time.TimeSeries;
+import org.jfree.data.time.TimeSeriesCollection;
+
+import com.redhat.thermostat.client.core.views.HostCpuView;
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.client.swing.components.LabelField;
+import com.redhat.thermostat.client.swing.components.RecentTimeSeriesChartPanel;
+import com.redhat.thermostat.client.swing.components.SectionHeader;
+import com.redhat.thermostat.client.swing.components.ValueField;
+import com.redhat.thermostat.client.swing.internal.WrapLayout;
+import com.redhat.thermostat.client.ui.ChartColors;
+import com.redhat.thermostat.client.ui.ComponentVisibleListener;
+import com.redhat.thermostat.client.ui.RecentTimeSeriesChartController;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
+
+public class HostCpuPanel extends HostCpuView implements SwingComponent {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private JPanel visiblePanel;
+
+    private final JTextComponent cpuModel = new ValueField("${CPU_MODEL}");
+    private final JTextComponent cpuCount = new ValueField("${CPU_COUNT}");
+
+    private final TimeSeriesCollection datasetCollection = new TimeSeriesCollection();
+    private final Map<Integer, TimeSeries> datasets = new HashMap<>();
+    private final Map<String, Color> colors = new HashMap<>();
+    private final Map<String, JLabel> labels = new HashMap<>();
+
+    private JFreeChart chart;
+
+    private JPanel legendPanel;
+
+    public HostCpuPanel() {
+        super();
+        initializePanel();
+
+        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+            @Override
+            public void componentHidden(Component component) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
+    }
+
+    @Override
+    public void addActionListener(ActionListener<Action> listener) {
+       notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeActionListener(ActionListener<Action> listener) {
+        notifier.removeActionListener(listener);
+    }
+
+    @Override
+    public void setCpuCount(final String count) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                cpuCount.setText(count);
+            }
+        });
+    }
+
+    @Override
+    public void setCpuModel(final String model) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                cpuModel.setText(model);
+            }
+        });
+    }
+
+    @Override
+    public void addCpuUsageChart(final int cpuIndex, final String humanReadableName) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                TimeSeries series = new TimeSeries(humanReadableName);
+                Color color = ChartColors.getColor(colors.size());
+                colors.put(humanReadableName, color);
+
+                datasets.put(cpuIndex, series);
+                datasetCollection.addSeries(series);
+
+                updateColors();
+
+                JLabel label = createLabelWithLegend(humanReadableName, color);
+                labels.put(humanReadableName, label);
+
+                legendPanel.add(label);
+                legendPanel.revalidate();
+            }
+        });
+    }
+
+    @Override
+    public void addCpuUsageData(final int cpuIndex, List<DiscreteTimeData<Double>> data) {
+        final ArrayList<DiscreteTimeData<Double>> copy = new ArrayList<>(data);
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                TimeSeries dataset = datasets.get(cpuIndex);
+                for (DiscreteTimeData<Double> timeData: copy) {
+                    RegularTimePeriod period = new FixedMillisecond(timeData.getTimeInMillis());
+                    if (dataset.getDataItem(period) == null) {
+                        dataset.add(period, timeData.getData(), false);
+                    }
+                }
+                dataset.fireSeriesChanged();
+            }
+        });
+    }
+
+    @Override
+    public void clearCpuUsageData() {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                for (Iterator<Map.Entry<Integer, TimeSeries>> iter = datasets.entrySet().iterator(); iter.hasNext();) {
+                    Map.Entry<Integer, TimeSeries> entry = iter.next();
+                    datasetCollection.removeSeries(entry.getValue());
+                    entry.getValue().clear();
+
+                    iter.remove();
+
+                }
+                updateColors();
+            }
+        });
+    }
+
+    @Override
+    public Component getUiComponent() {
+        return visiblePanel;
+    }
+
+    private void initializePanel() {
+
+        visiblePanel = new JPanel();
+
+        JLabel summaryLabel = new SectionHeader(translator.localize(LocaleResources.HOST_CPU_SECTION_OVERVIEW));
+
+        JLabel cpuModelLabel = new LabelField(translator.localize(LocaleResources.HOST_INFO_CPU_MODEL));
+
+        JLabel cpuCountLabel = new LabelField(translator.localize(LocaleResources.HOST_INFO_CPU_COUNT));
+
+        chart = ChartFactory.createTimeSeriesChart(
+                null,
+                translator.localize(LocaleResources.HOST_CPU_USAGE_CHART_TIME_LABEL),
+                translator.localize(LocaleResources.HOST_CPU_USAGE_CHART_VALUE_LABEL),
+                datasetCollection,
+                false, false, false);
+
+        chart.getPlot().setBackgroundPaint( new Color(255,255,255,0) );
+        chart.getPlot().setBackgroundImageAlpha(0.0f);
+        chart.getPlot().setOutlinePaint(new Color(0,0,0,0));
+
+        JPanel chartPanel = new RecentTimeSeriesChartPanel(new RecentTimeSeriesChartController(chart));
+        chartPanel.setOpaque(false);
+
+        legendPanel = new JPanel(new WrapLayout(FlowLayout.LEADING));
+        legendPanel.setOpaque(false);
+
+        GroupLayout groupLayout = new GroupLayout(visiblePanel);
+        groupLayout.setHorizontalGroup(
+            groupLayout.createParallelGroup(Alignment.TRAILING)
+                .addGroup(groupLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
+                        .addComponent(legendPanel, GroupLayout.DEFAULT_SIZE, 427, Short.MAX_VALUE)
+                        .addComponent(chartPanel, GroupLayout.DEFAULT_SIZE, 427, Short.MAX_VALUE)
+                        .addComponent(summaryLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                        .addGroup(groupLayout.createSequentialGroup()
+                            .addGap(12)
+                            .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
+                                .addGroup(groupLayout.createSequentialGroup()
+                                    .addPreferredGap(ComponentPlacement.RELATED)
+                                    .addComponent(cpuCountLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                                    .addGap(18)
+                                    .addComponent(cpuCount, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                                .addGroup(groupLayout.createSequentialGroup()
+                                    .addComponent(cpuModelLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                                    .addGap(18)
+                                    .addComponent(cpuModel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))
+                    .addGap(11))
+        );
+        groupLayout.setVerticalGroup(
+            groupLayout.createParallelGroup(Alignment.LEADING)
+                .addGroup(groupLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addComponent(summaryLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
+                        .addComponent(cpuModelLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                        .addComponent(cpuModel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                    .addGap(10)
+                    .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
+                        .addComponent(cpuCount, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                        .addComponent(cpuCountLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                    .addGap(18)
+                    .addComponent(chartPanel, GroupLayout.DEFAULT_SIZE, 263, Short.MAX_VALUE)
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addComponent(legendPanel, GroupLayout.PREFERRED_SIZE, 30, GroupLayout.PREFERRED_SIZE)
+                    .addContainerGap())
+        );
+        visiblePanel.setLayout(groupLayout);
+    }
+
+    /**
+     * Adding or removing series to the series collection may change the order
+     * of existing items. Plus the paint for the index is now out-of-date. So
+     * let's walk through all the series and set the right paint for those.
+     */
+    private void updateColors() {
+        XYItemRenderer itemRenderer = chart.getXYPlot().getRenderer();
+        for (int i = 0; i < datasetCollection.getSeriesCount(); i++) {
+            String tag = (String) datasetCollection.getSeriesKey(i);
+            Color color = colors.get(tag);
+            itemRenderer.setSeriesPaint(i, color);
+        }
+    }
+
+    private JLabel createLabelWithLegend(String text, Color color) {
+        String hexColor = "#" + Integer.toHexString(color.getRGB() & 0x00ffffff);
+        return new JLabel("<html> <font color='" + hexColor + "'>\u2588</font> " + text + "</html>");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/HostInformationPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.views;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import javax.swing.SwingUtilities;
+
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.core.views.HostInformationView;
+import com.redhat.thermostat.client.swing.SwingComponent;
+
+public class HostInformationPanel extends HostInformationView implements SwingComponent {
+
+    private JPanel visiblePanel;
+    private final JTabbedPane tabPane;
+
+    private int viewCount = 0;
+
+    public HostInformationPanel() {
+        super();
+        visiblePanel = new JPanel();
+        visiblePanel.setLayout(new BorderLayout());
+        tabPane = new JTabbedPane();
+        visiblePanel.add(tabPane);
+    }
+
+    @Override
+    public void addChildView(final String title, final BasicView view) {
+        if (view instanceof SwingComponent) {
+            final SwingComponent component = (SwingComponent)view;
+            SwingUtilities.invokeLater(new Runnable() {
+                @Override
+                public void run() {
+                    tabPane.insertTab(title, null, component.getUiComponent(), null, viewCount);
+                    viewCount++;
+                }
+                
+            });
+        }
+    }
+
+    @Override
+    public void removeChildView(final String title) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < viewCount; i++) {
+                    if (tabPane.getTitleAt(i).equals(title)) {
+                        tabPane.remove(i);
+                        return;
+                    }
+                }
+            }
+        });
+    }
+
+    @Override
+    public Component getUiComponent() {
+        return visiblePanel;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/HostMemoryPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,354 @@
+/*
+ * 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.swing.views;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.swing.GroupLayout;
+import javax.swing.GroupLayout.Alignment;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.LayoutStyle.ComponentPlacement;
+import javax.swing.SwingUtilities;
+import javax.swing.text.JTextComponent;
+
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.renderer.xy.XYItemRenderer;
+import org.jfree.data.time.FixedMillisecond;
+import org.jfree.data.time.RegularTimePeriod;
+import org.jfree.data.time.TimeSeries;
+import org.jfree.data.time.TimeSeriesCollection;
+
+import com.redhat.thermostat.client.core.views.HostMemoryView;
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.client.swing.components.Components;
+import com.redhat.thermostat.client.swing.components.RecentTimeSeriesChartPanel;
+import com.redhat.thermostat.client.swing.components.ValueField;
+import com.redhat.thermostat.client.swing.internal.WrapLayout;
+import com.redhat.thermostat.client.ui.ChartColors;
+import com.redhat.thermostat.client.ui.ComponentVisibleListener;
+import com.redhat.thermostat.client.ui.RecentTimeSeriesChartController;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
+import com.redhat.thermostat.common.utils.DisplayableValues;
+import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
+
+public class HostMemoryPanel extends HostMemoryView implements SwingComponent {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private JPanel visiblePanel;
+
+    private final MemoryCheckboxListener memoryCheckboxListener = new MemoryCheckboxListener();
+
+    private final JTextComponent totalMemory = new ValueField("${TOTAL_MEMORY}");
+
+    private final JPanel memoryCheckBoxPanel = new JPanel(new WrapLayout(FlowLayout.LEADING));
+    private final CopyOnWriteArrayList<GraphVisibilityChangeListener> listeners = new CopyOnWriteArrayList<>();
+    private final TimeSeriesCollection memoryCollection = new TimeSeriesCollection();
+    private final Map<String, TimeSeries> dataset = new HashMap<>();
+    private final Map<String, JCheckBox> checkBoxes = new HashMap<>();
+    private final Map<String, Color> colors = new HashMap<>();
+
+    private JFreeChart chart;
+
+    public HostMemoryPanel() {
+        super();
+        initializePanel();
+
+        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+            @Override
+            public void componentHidden(Component component) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
+    }
+
+    @Override
+    public void setTotalMemory(final String newValue) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                totalMemory.setText(newValue);
+            }
+        });
+    }
+
+    @Override
+    public Component getUiComponent() {
+        return visiblePanel;
+    }
+
+    @Override
+    public void addMemoryChart(final String tag, final String humanReadableName) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                int colorIndex = colors.size();
+                colors.put(tag, ChartColors.getColor(colorIndex));
+                TimeSeries series = new TimeSeries(tag);
+                dataset.put(tag, series);
+                JCheckBox newCheckBox = new JCheckBox(createLabelWithLegend(humanReadableName, colors.get(tag)));
+                newCheckBox.setActionCommand(tag);
+                newCheckBox.setSelected(true);
+                newCheckBox.addActionListener(memoryCheckboxListener);
+                newCheckBox.setOpaque(false);
+                checkBoxes.put(tag, newCheckBox);
+                memoryCheckBoxPanel.add(newCheckBox);
+
+                updateColors();
+            }
+        });
+
+    }
+
+    private String createLabelWithLegend(String text, Color color) {
+        String hexColor = "#" + Integer.toHexString(color.getRGB() & 0x00ffffff);
+        return "<html> <font color='" + hexColor + "'>\u2588</font> " + text + "</html>";
+    }
+
+    @Override
+    public void removeMemoryChart(final String tag) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                TimeSeries series = dataset.remove(tag);
+                memoryCollection.removeSeries(series);
+                JCheckBox box = checkBoxes.remove(tag);
+                memoryCheckBoxPanel.remove(box);
+
+                updateColors();
+            }
+        });
+    }
+
+    @Override
+    public void showMemoryChart(final String tag) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                TimeSeries series = dataset.get(tag);
+                memoryCollection.addSeries(series);
+
+                updateColors();
+            }
+        });
+    }
+
+    @Override
+    public void hideMemoryChart(final String tag) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                TimeSeries series = dataset.get(tag);
+                memoryCollection.removeSeries(series);
+
+                updateColors();
+            }
+        });
+    }
+
+    @Override
+    public void addMemoryData(final String tag, List<DiscreteTimeData<? extends Number>> data) {
+        final List<DiscreteTimeData<? extends Number>> copy = new ArrayList<>(data);
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                final TimeSeries series = dataset.get(tag);
+                for (DiscreteTimeData<? extends Number> timeData: copy) {
+                    RegularTimePeriod period = new FixedMillisecond(timeData.getTimeInMillis());
+                    if (series.getDataItem(period) == null) {
+                        Long sizeInBytes = (Long) timeData.getData();
+                        Double sizeInMegaBytes = DisplayableValues.Scale.convertTo(Scale.MiB, sizeInBytes);
+                        series.add(new FixedMillisecond(timeData.getTimeInMillis()), sizeInMegaBytes, false);
+                    }
+                }
+                series.fireSeriesChanged();
+            }
+        });
+    }
+
+    @Override
+    public void clearMemoryData(final String tag) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                TimeSeries series = dataset.get(tag);
+                series.clear();
+            }
+        });
+    }
+
+    @Override
+    public void addGraphVisibilityListener(GraphVisibilityChangeListener listener) {
+        listeners.add(listener);
+    }
+
+    @Override
+    public void removeGraphVisibilityListener(GraphVisibilityChangeListener listener) {
+        listeners.remove(listener);
+    }
+
+    @Override
+    public void addActionListener(ActionListener<Action> listener) {
+        notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeActionListener(ActionListener<Action> listener) {
+        notifier.removeActionListener(listener);
+    }
+
+    private void initializePanel() {
+        visiblePanel = new JPanel();
+        visiblePanel.setOpaque(false);
+
+        chart = createMemoryChart();
+
+        JPanel chartPanel = new RecentTimeSeriesChartPanel(new RecentTimeSeriesChartController(chart));
+        chartPanel.setOpaque(false);
+
+        JLabel lblMemory = Components.header(translator.localize(LocaleResources.HOST_MEMORY_SECTION_OVERVIEW));
+
+        JLabel totalMemoryLabel = Components.label(translator.localize(LocaleResources.HOST_INFO_MEMORY_TOTAL));
+
+        memoryCheckBoxPanel.setOpaque(false);
+
+        GroupLayout groupLayout = new GroupLayout(visiblePanel);
+        groupLayout.setHorizontalGroup(
+            groupLayout.createParallelGroup(Alignment.LEADING)
+                .addGroup(groupLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
+                        .addComponent(chartPanel, GroupLayout.DEFAULT_SIZE, 883, Short.MAX_VALUE)
+                        .addGroup(groupLayout.createSequentialGroup()
+                            .addGap(12)
+                            .addComponent(totalMemoryLabel)
+                            .addPreferredGap(ComponentPlacement.RELATED)
+                            .addComponent(totalMemory, GroupLayout.DEFAULT_SIZE, 751, Short.MAX_VALUE))
+                        .addComponent(lblMemory)
+                        .addComponent(memoryCheckBoxPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE))
+                    .addContainerGap())
+        );
+        groupLayout.setVerticalGroup(
+            groupLayout.createParallelGroup(Alignment.LEADING)
+                .addGroup(groupLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addComponent(lblMemory)
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
+                        .addComponent(totalMemory, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                        .addComponent(totalMemoryLabel))
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addComponent(chartPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addComponent(memoryCheckBoxPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
+                    .addContainerGap())
+        );
+        visiblePanel.setLayout(groupLayout);
+    }
+
+    private JFreeChart createMemoryChart() {
+        JFreeChart chart = ChartFactory.createTimeSeriesChart(
+                translator.localize(LocaleResources.HOST_MEMORY_CHART_TITLE), // Title
+                translator.localize(LocaleResources.HOST_MEMORY_CHART_TIME_LABEL), // x-axis Label
+                translator.localize(LocaleResources.HOST_MEMORY_CHART_SIZE_LABEL, Scale.MiB.name()), // y-axis Label
+                memoryCollection, // Dataset
+                false, // Show Legend
+                false, // Use tooltips
+                false // Configure chart to generate URLs?
+                );
+
+        chart.getPlot().setBackgroundPaint( new Color(255,255,255,0) );
+        chart.getPlot().setBackgroundImageAlpha(0.0f);
+        chart.getPlot().setOutlinePaint(new Color(0,0,0,0));
+
+        NumberAxis rangeAxis = (NumberAxis) chart.getXYPlot().getRangeAxis();
+        rangeAxis.setAutoRangeMinimumSize(100);
+
+        return chart;
+    }
+
+    private void fireShowHideHandlers(boolean show, String tag) {
+        for (GraphVisibilityChangeListener listener: listeners) {
+            if (show) {
+                listener.show(tag);
+            } else {
+                listener.hide(tag);
+            }
+        }
+    }
+
+    /**
+     * Adding or removing series to the series collection may change the order
+     * of existing items. Plus the paint for the index is now out-of-date. So
+     * let's walk through all the series and set the right paint for those.
+     */
+    private void updateColors() {
+        XYItemRenderer itemRenderer = chart.getXYPlot().getRenderer();
+        for (int i = 0; i < memoryCollection.getSeriesCount(); i++) {
+            String tag = (String) memoryCollection.getSeriesKey(i);
+            Color color = colors.get(tag);
+            itemRenderer.setSeriesPaint(i, color);
+        }
+    }
+
+    private class MemoryCheckboxListener implements java.awt.event.ActionListener {
+        @Override
+        public void actionPerformed(java.awt.event.ActionEvent e) {
+            JCheckBox source = (JCheckBox) e.getSource();
+            fireShowHideHandlers(source.isSelected(), source.getActionCommand());
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/HostOverviewPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,309 @@
+/*
+ * 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.swing.views;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+
+import javax.swing.GroupLayout;
+import javax.swing.GroupLayout.Alignment;
+import javax.swing.JPanel;
+import javax.swing.JTable;
+import javax.swing.LayoutStyle.ComponentPlacement;
+import javax.swing.SwingUtilities;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.JTableHeader;
+
+import com.redhat.thermostat.client.core.views.HostOverviewView;
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.client.swing.components.LabelField;
+import com.redhat.thermostat.client.swing.components.SectionHeader;
+import com.redhat.thermostat.client.swing.components.ValueField;
+import com.redhat.thermostat.client.ui.ComponentVisibleListener;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.locale.Translate;
+
+public class HostOverviewPanel extends HostOverviewView implements SwingComponent {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private JPanel visiblePanel;
+
+    private final ValueField hostname = new ValueField("${hostname}");
+    private final ValueField cpuModel = new ValueField("${cpu-model}");
+    private final ValueField cpuCount = new ValueField("${cpu-count}");
+    private final ValueField totalMemory = new ValueField("${total-memory}");
+    private final ValueField osName = new ValueField("${os-name}");
+    private final ValueField osKernel = new ValueField("${os-kernel}");
+
+    private final DefaultTableModel networkTableModel = new DefaultTableModel() {
+        @Override
+        public boolean isCellEditable(int row, int column) {
+            return false;
+        }
+    };
+
+    private Object[] networkTableColumns;
+    private Object[][] networkTableData;
+
+    public HostOverviewPanel() {
+        super();
+        initializePanel();
+
+        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+
+            @Override
+            public void componentHidden(Component component) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
+    }
+
+    @Override
+    public void addActionListener(ActionListener<Action> listener) {
+        notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeActionListener(ActionListener<Action> listener) {
+        notifier.removeActionListener(listener);
+    }
+
+    @Override
+    public void setHostName(final String newHostName) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                hostname.setText(newHostName);
+            }
+        });
+    }
+
+    @Override
+    public void setCpuModel(final String newCpuModel) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                cpuModel.setText(newCpuModel);
+            }
+        });
+    }
+
+    @Override
+    public void setCpuCount(final String newCpuCount) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                cpuCount.setText(newCpuCount);
+            }
+        });
+    }
+
+    @Override
+    public void setTotalMemory(final String newTotalMemory) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                totalMemory.setText(newTotalMemory);
+            }
+        });
+    }
+
+    @Override
+    public void setOsName(final String newOsName) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                osName.setText(newOsName);
+            }
+        });
+    }
+
+    @Override
+    public void setOsKernel(final String newOsKernel) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                osKernel.setText(newOsKernel);
+            }
+        });
+    }
+
+    @Override
+    public void setNetworkTableColumns(final Object[] columns) {
+        this.networkTableColumns = columns;
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                networkTableModel.setColumnIdentifiers(networkTableColumns);
+            }
+        });
+    }
+
+    @Override
+    public void setInitialNetworkTableData(final Object[][] data) {
+        this.networkTableData = data;
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                networkTableModel.setDataVector(networkTableData, networkTableColumns);
+            }
+        });
+    }
+
+    @Override
+    public void updateNetworkTableData(final int row, final int column, final String data) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                networkTableModel.setValueAt(data, row, column);
+            }
+        });
+    }
+
+    @Override
+    public Component getUiComponent() {
+        return visiblePanel;
+    }
+
+    private void initializePanel() {
+        visiblePanel = new JPanel();
+        SectionHeader overviewSection = new SectionHeader(translator.localize(LocaleResources.HOST_OVERVIEW_SECTION_BASICS));
+        LabelField hostnameLabel = new LabelField(translator.localize(LocaleResources.HOST_INFO_HOSTNAME));
+        SectionHeader hardwareSection = new SectionHeader(translator.localize(LocaleResources.HOST_OVERVIEW_SECTION_HARDWARE));
+        LabelField cpuModelLabel = new LabelField(translator.localize(LocaleResources.HOST_INFO_CPU_MODEL));
+        LabelField cpuCountLabel = new LabelField(translator.localize(LocaleResources.HOST_INFO_CPU_COUNT));
+        LabelField memoryTotalLabel = new LabelField(translator.localize(LocaleResources.HOST_INFO_MEMORY_TOTAL));
+        LabelField networkLabel = new LabelField(translator.localize(LocaleResources.HOST_INFO_NETWORK));
+        SectionHeader softwareSection = new SectionHeader(translator.localize(LocaleResources.HOST_OVERVIEW_SECTION_SOFTWARE));
+        LabelField osNameLabel = new LabelField(translator.localize(LocaleResources.HOST_INFO_OS_NAME));
+        LabelField osKernelLabel = new LabelField(translator.localize(LocaleResources.HOST_INFO_OS_KERNEL));
+
+        JPanel panel = new JPanel();
+
+        GroupLayout gl_visiblePanel = new GroupLayout(visiblePanel);
+        gl_visiblePanel.setHorizontalGroup(
+            gl_visiblePanel.createParallelGroup(Alignment.LEADING)
+                .addGroup(gl_visiblePanel.createSequentialGroup()
+                    .addContainerGap()
+                    .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING)
+                        .addComponent(hardwareSection, GroupLayout.DEFAULT_SIZE, 620, Short.MAX_VALUE)
+                        .addComponent(overviewSection, GroupLayout.DEFAULT_SIZE, 620, Short.MAX_VALUE)
+                        .addGroup(gl_visiblePanel.createSequentialGroup()
+                            .addGroup(gl_visiblePanel.createParallelGroup(Alignment.TRAILING, false)
+                                .addGroup(gl_visiblePanel.createSequentialGroup()
+                                    .addGap(12)
+                                    .addComponent(hostnameLabel, GroupLayout.DEFAULT_SIZE, 134, Short.MAX_VALUE))
+                                .addComponent(cpuCountLabel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                                .addComponent(cpuModelLabel, GroupLayout.DEFAULT_SIZE, 134, Short.MAX_VALUE)
+                                .addComponent(memoryTotalLabel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                                .addGroup(gl_visiblePanel.createSequentialGroup()
+                                    .addGap(12)
+                                    .addComponent(networkLabel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
+                            .addPreferredGap(ComponentPlacement.RELATED)
+                            .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING)
+                                .addComponent(panel, GroupLayout.DEFAULT_SIZE, 462, Short.MAX_VALUE)
+                                .addComponent(cpuCount, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                                .addComponent(cpuModel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                                .addComponent(hostname, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                                .addComponent(totalMemory, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
+                        .addComponent(softwareSection, GroupLayout.DEFAULT_SIZE, 620, Short.MAX_VALUE)
+                        .addGroup(gl_visiblePanel.createSequentialGroup()
+                            .addGap(12)
+                            .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING, false)
+                                .addComponent(osKernelLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                                .addComponent(osNameLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 129, Short.MAX_VALUE))
+                            .addPreferredGap(ComponentPlacement.RELATED)
+                            .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING)
+                                .addComponent(osKernel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                                .addComponent(osName, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
+                    .addContainerGap())
+        );
+        gl_visiblePanel.setVerticalGroup(
+            gl_visiblePanel.createParallelGroup(Alignment.LEADING)
+                .addGroup(gl_visiblePanel.createSequentialGroup()
+                    .addContainerGap()
+                    .addComponent(overviewSection, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING, false)
+                        .addComponent(hostname, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE)
+                        .addComponent(hostnameLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                    .addPreferredGap(ComponentPlacement.UNRELATED)
+                    .addComponent(hardwareSection, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING, false)
+                        .addComponent(cpuModelLabel, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE)
+                        .addComponent(cpuModel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING, false)
+                        .addComponent(cpuCountLabel, GroupLayout.PREFERRED_SIZE, 15, GroupLayout.PREFERRED_SIZE)
+                        .addComponent(cpuCount, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING)
+                        .addComponent(memoryTotalLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                        .addComponent(totalMemory, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING)
+                        .addComponent(networkLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                        .addComponent(panel, GroupLayout.PREFERRED_SIZE, 109, GroupLayout.PREFERRED_SIZE))
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addComponent(softwareSection, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING)
+                        .addComponent(osNameLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                        .addComponent(osName, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addGroup(gl_visiblePanel.createParallelGroup(Alignment.LEADING)
+                        .addComponent(osKernelLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+                        .addComponent(osKernel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                    .addGap(128))
+        );
+
+        panel.setLayout(new BorderLayout(0, 0));
+
+        JTable networkTable = new JTable(networkTableModel);
+        panel.add(networkTable);
+        JTableHeader header = networkTable.getTableHeader();
+        panel.add(header, BorderLayout.PAGE_START);
+        visiblePanel.setLayout(gl_visiblePanel);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/MemorySpacePanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,112 @@
+/*
+ * 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.swing.views;
+
+import javax.swing.GroupLayout;
+import javax.swing.GroupLayout.Alignment;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.LayoutStyle.ComponentPlacement;
+
+import com.redhat.thermostat.client.swing.IconResource;
+
+
+public class MemorySpacePanel extends JPanel {
+
+    private final JProgressBar percentagePanel;
+    private final JLabel additionalDetailsIcon;
+    private final JLabel lblUsed;
+    private final JLabel lblAvailable;
+
+    public MemorySpacePanel(String regionName) {
+        JLabel lblRegionName = new JLabel(regionName);
+
+        percentagePanel = new JProgressBar(0, 100);
+
+        additionalDetailsIcon = new JLabel(IconResource.ARROW_RIGHT.getIcon());
+
+        lblUsed = new JLabel("${USED}");
+        lblAvailable = new JLabel("${AVAILABLE}");
+
+        GroupLayout groupLayout = new GroupLayout(this);
+        groupLayout.setHorizontalGroup(
+            groupLayout.createParallelGroup(Alignment.LEADING)
+                .addGroup(groupLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
+                        .addComponent(lblRegionName)
+                        .addGroup(groupLayout.createSequentialGroup()
+                            .addGap(12)
+                            .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
+                                .addComponent(percentagePanel, GroupLayout.DEFAULT_SIZE, 574, Short.MAX_VALUE)
+                                .addGroup(groupLayout.createSequentialGroup()
+                                    .addComponent(lblUsed)
+                                    .addPreferredGap(ComponentPlacement.RELATED, 441, Short.MAX_VALUE)
+                                    .addComponent(lblAvailable)))))
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addComponent(additionalDetailsIcon)
+                    .addContainerGap())
+        );
+        groupLayout.setVerticalGroup(
+            groupLayout.createParallelGroup(Alignment.LEADING)
+                .addGroup(groupLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addComponent(lblRegionName)
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
+                        .addComponent(additionalDetailsIcon, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                        .addComponent(percentagePanel, GroupLayout.DEFAULT_SIZE, 44, Short.MAX_VALUE))
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
+                        .addComponent(lblUsed)
+                        .addComponent(lblAvailable))
+                    .addGap(5))
+        );
+        setLayout(groupLayout);
+    }
+
+
+    public void updateRegionData(int percentageUsed, String currentlyUsed, String currentlyAvailable, String allocatable) {
+        percentagePanel.setValue(percentageUsed);
+
+        lblUsed.setText(currentlyUsed);
+        lblAvailable.setText(currentlyAvailable);
+        additionalDetailsIcon.setToolTipText(allocatable);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/SearchFieldSwingView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,226 @@
+/*
+ * 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.swing.views;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.swing.BorderFactory;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+
+import com.redhat.thermostat.client.core.views.SearchFieldView;
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.swing.IconResource;
+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;
+
+public class SearchFieldSwingView extends JPanel implements SearchFieldView {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private final ActionNotifier<SearchAction> notifier = new ActionNotifier<>(this);
+    private final JTextField searchField = new JTextField();
+
+    private final AtomicReference<String> searchText = new AtomicReference<String>("");
+    private final AtomicReference<String> label = new AtomicReference<>(translator.localize(LocaleResources.SEARCH_HINT));
+    private final AtomicBoolean labelDisplayed = new AtomicBoolean(true);
+
+    public SearchFieldSwingView() {
+        super(new BorderLayout());
+
+        // TODO move this icon inside the search field
+        JLabel searchIcon = new JLabel(IconResource.SEARCH.getIcon());
+        searchIcon.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+
+        searchField.setText(label.get());
+        searchField.setName(VIEW_NAME);
+        /* the insets are so we can place the actual icon inside the searchField */
+        searchField.setMargin(new Insets(0, 0, 0, 30));
+
+        searchField.getDocument().addDocumentListener(new DocumentListener() {
+
+            private String previousText = searchText.get();
+
+            @Override
+            public void removeUpdate(DocumentEvent event) {
+                changed(event.getDocument());
+            }
+
+            @Override
+            public void insertUpdate(DocumentEvent event) {
+                changed(event.getDocument());
+            }
+
+            @Override
+            public void changedUpdate(DocumentEvent event) {
+                changed(event.getDocument());
+            }
+
+            private void changed(Document doc) {
+                if (!labelDisplayed.get()) {
+                    String filter = null;
+                    try {
+                        filter = doc.getText(0, doc.getLength());
+                    } catch (BadLocationException ble) {
+                        // ignore
+                    }
+
+                    searchText.set(filter);
+                    if (!(filter.equals(previousText))) {
+                        previousText = filter;
+                        fireViewAction(SearchAction.TEXT_CHANGED);
+                    }
+                }
+            }
+        });
+
+        final Color originalForegroundColor = searchField.getForeground();
+        searchField.addFocusListener(new FocusListener() {
+
+            @Override
+            public void focusLost(FocusEvent e) {
+                if (searchText.get().equals("")) {
+                    labelDisplayed.set(true);
+                    searchField.setForeground(Color.GRAY);
+                    searchField.setText(label.get());
+                }
+            }
+
+            @Override
+            public void focusGained(FocusEvent e) {
+                if (labelDisplayed.get()) {
+                    labelDisplayed.set(false);
+                    searchField.setForeground(originalForegroundColor);
+                    searchField.setText("");
+                }
+
+            }
+        });
+
+        final java.awt.event.ActionListener searchActionListener = new java.awt.event.ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                fireViewAction(SearchAction.PERFORM_SEARCH);
+            }
+        };
+
+        searchField.addActionListener(searchActionListener);
+
+        add(searchField);
+        add(searchIcon, BorderLayout.LINE_END);
+
+    }
+
+    @Override
+    public String getSearchText() {
+        try {
+            return new EdtHelper().callAndWait(new Callable<String>() {
+                @Override
+                public String call() throws Exception {
+                    return searchText.get();
+                }
+            });
+        } catch (InvocationTargetException | InterruptedException e) {
+            return null;
+        }
+    }
+
+    @Override
+    public void setSearchText(final String text) {
+        searchText.set(text);
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                searchField.setText(text);
+            }
+        });
+    }
+
+    @Override
+    public void setLabel(String label) {
+        this.label.set(label);
+        if (labelDisplayed.get()) {
+            SwingUtilities.invokeLater(new Runnable() {
+                @Override
+                public void run() {
+                    searchField.setText(SearchFieldSwingView.this.label.get());
+                }
+            });
+        }
+    }
+
+    @Override
+    public void setTooltip(final String tooltip) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                searchField.setToolTipText(tooltip);
+            }
+        });
+    }
+
+    @Override
+    public void addActionListener(ActionListener<SearchAction> listener) {
+        notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeActionListener(ActionListener<SearchAction> listener) {
+        notifier.removeActionListener(listener);
+    }
+
+    private void fireViewAction(SearchAction action) {
+        notifier.fireAction(action);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/SummaryPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,220 @@
+/*
+ * 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.swing.views;
+
+import java.awt.Component;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.AbstractListModel;
+import javax.swing.GroupLayout;
+import javax.swing.GroupLayout.Alignment;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.LayoutStyle.ComponentPlacement;
+import javax.swing.ListModel;
+import javax.swing.SwingUtilities;
+import javax.swing.text.JTextComponent;
+
+import com.redhat.thermostat.client.core.views.SummaryView;
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.client.swing.components.Components;
+import com.redhat.thermostat.client.swing.components.ValueField;
+import com.redhat.thermostat.client.ui.ComponentVisibleListener;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.locale.Translate;
+
+public class SummaryPanel extends SummaryView implements SwingComponent {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private JPanel visiblePanel;
+    
+    private final JTextComponent totalMonitoredHosts;
+    private final JTextComponent totalMonitoredVms;
+
+    private final List<String> issuesList;
+
+    public SummaryPanel() {
+        super();
+        visiblePanel = new JPanel();
+        JLabel lblHomepanel = Components.header(translator.localize(LocaleResources.HOME_PANEL_SECTION_SUMMARY));
+
+        JLabel lblTotalHosts = new JLabel(translator.localize(LocaleResources.HOME_PANEL_TOTAL_MACHINES));
+
+        totalMonitoredHosts = new ValueField("${TOTAL_MONITORED_HOSTS}");
+
+        JLabel lblTotal = new JLabel(translator.localize(LocaleResources.HOME_PANEL_TOTAL_JVMS));
+
+        totalMonitoredVms = new ValueField("${TOTAL_MONITORED_VMS}");
+
+        JLabel lblIssues = Components.header(translator.localize(LocaleResources.HOME_PANEL_SECTION_ISSUES));
+
+        JScrollPane scrollPane = new JScrollPane();
+
+        GroupLayout groupLayout = new GroupLayout(visiblePanel);
+        groupLayout.setHorizontalGroup(
+            groupLayout.createParallelGroup(Alignment.TRAILING)
+                .addGroup(groupLayout.createSequentialGroup()
+                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
+                        .addGroup(groupLayout.createSequentialGroup()
+                            .addContainerGap()
+                            .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
+                                .addComponent(lblHomepanel)
+                                .addGroup(groupLayout.createSequentialGroup()
+                                    .addGap(12)
+                                    .addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
+                                        .addComponent(lblTotal)
+                                        .addComponent(lblTotalHosts))
+                                    .addGap(18)
+                                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
+                                        .addComponent(totalMonitoredVms, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                                        .addComponent(totalMonitoredHosts, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
+                                .addComponent(lblIssues)))
+                        .addGroup(groupLayout.createSequentialGroup()
+                            .addGap(24)
+                            .addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
+                    .addContainerGap())
+        );
+        groupLayout.setVerticalGroup(
+            groupLayout.createParallelGroup(Alignment.LEADING)
+                .addGroup(groupLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .addComponent(lblHomepanel)
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
+                        .addComponent(lblTotalHosts)
+                        .addComponent(totalMonitoredHosts, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE))
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
+                        .addComponent(lblTotal)
+                        .addComponent(totalMonitoredVms, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+                    .addGap(18)
+                    .addComponent(lblIssues)
+                    .addPreferredGap(ComponentPlacement.RELATED)
+                    .addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addContainerGap())
+        );
+
+        issuesList = new ArrayList<>();
+        ListModel<Object> issuesListModel = new IssuesListModel(issuesList);
+        JList<Object> issuesList = new JList<>();
+        issuesList.setModel(issuesListModel);
+        scrollPane.setViewportView(issuesList);
+        visiblePanel.setLayout(groupLayout);
+
+        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+
+            @Override
+            public void componentHidden(Component component) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
+    }
+
+    @Override
+    public void addActionListener(ActionListener<Action> listener) {
+        notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeActionListener(ActionListener<Action> listener) {
+        notifier.removeActionListener(listener);
+    }
+
+    @Override
+    public void setTotalHosts(final String count) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                totalMonitoredHosts.setText(count);
+            }
+        });
+    }
+
+    @Override
+    public void setTotalVms(final String count) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                totalMonitoredVms.setText(count);
+            }
+        });
+    }
+
+    @Override
+    public Component getUiComponent() {
+        return visiblePanel;
+    }
+
+    private static class IssuesListModel extends AbstractListModel<Object> {
+
+        private static final long serialVersionUID = 7131506292620902850L;
+
+        private List<? extends Object> delegate;
+
+        private String emptyElement = translator.localize(LocaleResources.HOME_PANEL_NO_ISSUES);
+
+        public IssuesListModel(List<? extends Object> actualList) {
+            this.delegate = actualList;
+            // TODO observe the delegate for changes
+        }
+
+        @Override
+        public int getSize() {
+            if (delegate.isEmpty()) {
+                return 1;
+            }
+            return delegate.size();
+        }
+
+        @Override
+        public Object getElementAt(int index) {
+            if (delegate.isEmpty()) {
+                return emptyElement;
+            }
+            return delegate.get(index);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/SwingAgentInformationViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.views;
+
+import com.redhat.thermostat.client.core.views.AgentInformationDisplayView;
+import com.redhat.thermostat.client.core.views.AgentInformationViewProvider;
+
+public class SwingAgentInformationViewProvider implements
+        AgentInformationViewProvider {
+
+    @Override
+    public AgentInformationDisplayView createView() {
+        return new AgentInformationDisplayFrame();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/SwingClientConfigurationViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.views;
+
+import com.redhat.thermostat.client.core.views.ClientConfigViewProvider;
+import com.redhat.thermostat.client.core.views.ClientConfigurationView;
+
+public class SwingClientConfigurationViewProvider implements
+        ClientConfigViewProvider {
+
+    @Override
+    public ClientConfigurationView createView() {
+        return new ClientConfigurationSwing();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/SwingHostCpuViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.views;
+
+import com.redhat.thermostat.client.core.views.HostCpuView;
+import com.redhat.thermostat.client.core.views.HostCpuViewProvider;
+
+public class SwingHostCpuViewProvider implements HostCpuViewProvider {
+
+    @Override
+    public HostCpuView createView() {
+        return new HostCpuPanel();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/SwingHostInformationViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.views;
+
+import com.redhat.thermostat.client.core.views.HostInformationView;
+import com.redhat.thermostat.client.core.views.HostInformationViewProvider;
+
+public class SwingHostInformationViewProvider implements HostInformationViewProvider {
+
+    @Override
+    public HostInformationView createView() {
+        return new HostInformationPanel();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/SwingHostMemoryViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.views;
+
+import com.redhat.thermostat.client.core.views.HostMemoryView;
+import com.redhat.thermostat.client.core.views.HostMemoryViewProvider;
+
+public class SwingHostMemoryViewProvider implements HostMemoryViewProvider {
+
+    @Override
+    public HostMemoryView createView() {
+        return new HostMemoryPanel();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/SwingHostOverviewViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.views;
+
+import com.redhat.thermostat.client.core.views.HostOverviewView;
+import com.redhat.thermostat.client.core.views.HostOverviewViewProvider;
+
+public class SwingHostOverviewViewProvider implements HostOverviewViewProvider {
+
+    @Override
+    public HostOverviewView createView() {
+        return new HostOverviewPanel();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/SwingSummaryViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.views;
+
+import com.redhat.thermostat.client.core.views.SummaryView;
+import com.redhat.thermostat.client.core.views.SummaryViewProvider;
+
+public class SwingSummaryViewProvider implements SummaryViewProvider {
+
+    @Override
+    public SummaryView createView() {
+        return new SummaryPanel();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/SwingVmCpuViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.views;
+
+import com.redhat.thermostat.client.core.views.VmCpuView;
+import com.redhat.thermostat.client.core.views.VmCpuViewProvider;
+
+public class SwingVmCpuViewProvider implements VmCpuViewProvider {
+
+    @Override
+    public VmCpuView createView() {
+        return new VmCpuPanel();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/SwingVmGcViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.views;
+
+import com.redhat.thermostat.client.core.views.VmGcView;
+import com.redhat.thermostat.client.core.views.VmGcViewProvider;
+
+public class SwingVmGcViewProvider implements VmGcViewProvider {
+
+    @Override
+    public VmGcView createView() {
+        return new VmGcPanel();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/SwingVmInformationViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.views;
+
+import com.redhat.thermostat.client.core.views.VmInformationView;
+import com.redhat.thermostat.client.core.views.VmInformationViewProvider;
+
+public class SwingVmInformationViewProvider implements VmInformationViewProvider {
+
+    @Override
+    public VmInformationView createView() {
+        return new VmInformationPanel();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/SwingVmOverviewViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.views;
+
+import com.redhat.thermostat.client.core.views.VmOverviewView;
+import com.redhat.thermostat.client.core.views.VmOverviewViewProvider;
+
+public class SwingVmOverviewViewProvider implements VmOverviewViewProvider {
+
+    @Override
+    public VmOverviewView createView() {
+        return new VmOverviewPanel();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/VmCpuPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,151 @@
+/*
+ * 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.swing.views;
+
+import java.awt.Component;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.JFreeChart;
+import org.jfree.data.time.FixedMillisecond;
+import org.jfree.data.time.RegularTimePeriod;
+import org.jfree.data.time.TimeSeries;
+import org.jfree.data.time.TimeSeriesCollection;
+
+import com.redhat.thermostat.client.core.views.VmCpuView;
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.client.swing.components.HeaderPanel;
+import com.redhat.thermostat.client.swing.components.RecentTimeSeriesChartPanel;
+import com.redhat.thermostat.client.ui.ComponentVisibleListener;
+import com.redhat.thermostat.client.ui.RecentTimeSeriesChartController;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
+
+public class VmCpuPanel extends VmCpuView implements SwingComponent {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private HeaderPanel visiblePanel;
+    
+    private final TimeSeriesCollection data = new TimeSeriesCollection();
+    private final TimeSeries cpuTimeSeries = new TimeSeries("cpu-stats");
+
+    public VmCpuPanel() {
+        super();
+        data.addSeries(cpuTimeSeries);
+
+        initializePanel();
+
+        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+
+            @Override
+            public void componentHidden(Component component) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
+    }
+
+    @Override
+    public void addActionListener(ActionListener<Action> listener) {
+        notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeActionListener(ActionListener<Action> listener) {
+        notifier.removeActionListener(listener);
+    }
+
+    @Override
+    public Component getUiComponent() {
+        return visiblePanel;
+    }
+
+    private void initializePanel() {
+        visiblePanel = new HeaderPanel();
+        visiblePanel.setHeader(translator.localize(LocaleResources.VM_CPU_TITLE));
+
+        JFreeChart chart = ChartFactory.createTimeSeriesChart(
+                null,
+                translator.localize(LocaleResources.VM_CPU_CHART_TIME_LABEL),
+                translator.localize(LocaleResources.VM_CPU_CHART_LOAD_LABEL),
+                data,
+                false, false, false);
+
+        chart.getXYPlot().getRangeAxis().setLowerBound(0.0);
+
+        JPanel chartPanel = new RecentTimeSeriesChartPanel(new RecentTimeSeriesChartController(chart));
+
+        visiblePanel.setContent(chartPanel);
+    }
+
+    @Override
+    public void addData(List<DiscreteTimeData<? extends Number>> data) {
+        final List<DiscreteTimeData<? extends Number>> copy = new ArrayList<>(data);
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                for (DiscreteTimeData<? extends Number> data: copy) {
+                    RegularTimePeriod period = new FixedMillisecond(data.getTimeInMillis());
+                    if (cpuTimeSeries.getDataItem(period) == null) {
+                        cpuTimeSeries.add(period, data.getData(), false);
+                    }
+                }
+                cpuTimeSeries.fireSeriesChanged();
+            }
+        });
+    }
+
+    @Override
+    public void clearData() {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                cpuTimeSeries.clear();
+            }
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/VmGcPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,250 @@
+/*
+ * 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.swing.views;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+
+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.event.ChartProgressEvent;
+import org.jfree.chart.event.ChartProgressListener;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.StandardXYBarPainter;
+import org.jfree.chart.renderer.xy.XYBarRenderer;
+import org.jfree.data.RangeType;
+import org.jfree.data.xy.IntervalXYDataset;
+
+import com.redhat.thermostat.client.core.views.VmGcView;
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.client.swing.components.Components;
+import com.redhat.thermostat.client.swing.components.HeaderPanel;
+import com.redhat.thermostat.client.swing.components.RecentTimeSeriesChartPanel;
+import com.redhat.thermostat.client.ui.ComponentVisibleListener;
+import com.redhat.thermostat.client.ui.RecentTimeSeriesChartController;
+import com.redhat.thermostat.client.ui.SampledDataset;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.model.IntervalTimeData;
+
+public class VmGcPanel extends VmGcView implements SwingComponent {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private HeaderPanel visiblePanel = new HeaderPanel();
+    private JPanel realPanel = new JPanel();
+
+    private final Map<String, SampledDataset> dataset = new HashMap<>();
+    private final Map<String, JPanel> subPanels = new HashMap<>();
+
+    private final GridBagConstraints gcPanelConstraints;
+
+    public VmGcPanel() {
+        super();
+        initializePanel();
+
+        gcPanelConstraints = new GridBagConstraints();
+        gcPanelConstraints.gridx = 0;
+        gcPanelConstraints.gridy = 0;
+        gcPanelConstraints.fill = GridBagConstraints.BOTH;
+        gcPanelConstraints.weightx = 1;
+        gcPanelConstraints.weighty = 1;
+
+        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+
+            @Override
+            public void componentHidden(Component component) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
+    }
+
+    @Override
+    public void addActionListener(ActionListener<Action> listener) {
+        notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeActionListener(ActionListener<Action> listener) {
+        notifier.removeActionListener(listener);
+    }
+
+    @Override
+    public Component getUiComponent() {
+        return visiblePanel;
+    }
+
+    private void initializePanel() {
+        visiblePanel.setContent(realPanel);
+        visiblePanel.setHeader(translator.localize(LocaleResources.VM_GC_TITLE));
+        realPanel.setLayout(new GridBagLayout());
+    }
+
+    private JPanel createCollectorDetailsPanel(IntervalXYDataset collectorData, String title, String units) {
+        JPanel detailsPanel = new JPanel();
+        detailsPanel.setBorder(Components.smallBorder());
+        detailsPanel.setLayout(new BorderLayout());
+
+        detailsPanel.add(Components.header(title), BorderLayout.NORTH);
+
+        JFreeChart chart = ChartFactory.createHistogram(
+            null,
+            translator.localize(LocaleResources.VM_GC_COLLECTOR_CHART_REAL_TIME_LABEL),
+            translator.localize(LocaleResources.VM_GC_COLLECTOR_CHART_GC_TIME_LABEL, units),
+            collectorData,
+            PlotOrientation.VERTICAL,
+            false,
+            false,
+            false);
+
+        ((XYBarRenderer)(chart.getXYPlot().getRenderer())).setBarPainter(new StandardXYBarPainter());
+
+        setupPlotAxes(chart.getXYPlot());
+
+        chart.getXYPlot().setDomainCrosshairLockedOnData(true);
+        chart.getXYPlot().setDomainCrosshairVisible(true);
+
+        final RecentTimeSeriesChartPanel chartPanel = new RecentTimeSeriesChartPanel(new RecentTimeSeriesChartController(chart));
+
+        chart.addProgressListener(new ChartProgressListener() {
+
+            @Override
+            public void chartProgress(ChartProgressEvent event) {
+                if (event.getType() != ChartProgressEvent.DRAWING_FINISHED) {
+                    return;
+                }
+
+                double rangeCrossHairValue = event.getChart().getXYPlot().getRangeCrosshairValue();
+                chartPanel.setDataInformationLabel(String.valueOf(rangeCrossHairValue));
+            }
+        });
+
+        detailsPanel.add(chartPanel, BorderLayout.CENTER);
+
+        return detailsPanel;
+    }
+
+    private void setupPlotAxes(XYPlot plot) {
+        setupDomainAxis(plot);
+        setupRangeAxis(plot);
+    }
+
+    private void setupDomainAxis(XYPlot plot) {
+        plot.setDomainAxis(new DateAxis());
+    }
+
+    private void setupRangeAxis(XYPlot plot) {
+        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
+
+        rangeAxis.setRangeType(RangeType.POSITIVE);
+        rangeAxis.setAutoRange(true);
+        rangeAxis.setAutoRangeMinimumSize(1);
+    }
+
+    @Override
+    public void addChart(final String tag, final String title, final String units) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                SampledDataset newData = new SampledDataset();
+                dataset.put(tag, newData);
+                JPanel subPanel = createCollectorDetailsPanel(newData, title, units);
+                subPanels.put(tag, subPanel);
+                realPanel.add(subPanel, gcPanelConstraints);
+                gcPanelConstraints.gridy++;
+                realPanel.revalidate();
+            }
+        });
+    }
+
+    @Override
+    public void removeChart(final String tag) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                dataset.remove(tag);
+                JPanel subPanel = subPanels.remove(tag);
+                realPanel.remove(subPanel);
+                realPanel.revalidate();
+                gcPanelConstraints.gridy--;
+            }
+        });
+    }
+
+    @Override
+    public void addData(final String tag, List<IntervalTimeData<Double>> data) {
+        final List<IntervalTimeData<Double>> copy = new ArrayList<>(data);
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                SampledDataset series = dataset.get(tag);
+                for (IntervalTimeData<Double> timeData: copy) {
+                    series.add(timeData.getStartTimeInMillis(), timeData.getEndTimeInMillis(), timeData.getData());
+                }
+                series.fireSeriesChanged();
+            }
+        });
+    }
+
+    @Override
+    public void clearData(final String tag) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                SampledDataset series = dataset.get(tag);
+                series.clear();
+            }
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/VmInformationPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,95 @@
+/*
+ * 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.swing.views;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+
+import com.redhat.thermostat.client.core.views.UIComponent;
+import com.redhat.thermostat.client.core.views.VmInformationView;
+import com.redhat.thermostat.client.swing.SwingComponent;
+
+public class VmInformationPanel extends VmInformationView implements SwingComponent {
+
+    private final JTabbedPane tabPane = new JTabbedPane();
+    private JPanel visiblePanel;
+
+    private int tabCount = 0;
+
+    public VmInformationPanel() {
+        super();
+        visiblePanel = new JPanel();
+        visiblePanel.setLayout(new BorderLayout());
+        tabPane.setName("tabPane");
+        visiblePanel.add(tabPane);
+    }
+
+    @Override
+    public void addChildView(String title, UIComponent view) {
+        if (view instanceof SwingComponent) {
+            SwingComponent panel = (SwingComponent)view;
+            tabPane.insertTab(title, null, panel.getUiComponent(), null, tabCount);
+            tabCount++;
+        }
+    }
+
+    public Component getUiComponent() {
+        return visiblePanel;
+    }
+
+    @Override
+    public int getSelectedChildID() {
+        return tabPane.getSelectedIndex();
+    }
+
+    @Override
+    public boolean selectChildID(int id) {
+        if (tabPane.getComponentCount() > id) {
+            tabPane.setSelectedIndex(id);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public int getNumChildren() {
+        return tabPane.getComponentCount();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/VmOverviewPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,193 @@
+/*
+ * 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.swing.views;
+
+import java.awt.Component;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.JPanel;
+
+import com.redhat.thermostat.client.core.views.VmOverviewView;
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.client.swing.components.Components;
+import com.redhat.thermostat.client.swing.components.HeaderPanel;
+import com.redhat.thermostat.client.swing.components.SimpleTable;
+import com.redhat.thermostat.client.swing.components.SimpleTable.Section;
+import com.redhat.thermostat.client.swing.components.SimpleTable.TableEntry;
+import com.redhat.thermostat.client.swing.internal.ChangeableText;
+import com.redhat.thermostat.client.ui.ComponentVisibleListener;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.locale.Translate;
+
+public class VmOverviewPanel extends VmOverviewView implements SwingComponent {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+    
+    private HeaderPanel visiblePanel;
+
+    private final ChangeableText pid = new ChangeableText("");
+    private final ChangeableText startTimeStamp = new ChangeableText("");
+    private final ChangeableText stopTimeStamp = new ChangeableText("");
+    private final ChangeableText mainClass = new ChangeableText("");
+    private final ChangeableText javaCommandLine = new ChangeableText("");
+    private final ChangeableText javaHome = new ChangeableText("");
+    private final ChangeableText javaVersion = new ChangeableText("");
+    private final ChangeableText vmNameAndVersion = new ChangeableText("");
+    private final ChangeableText vmArguments = new ChangeableText("");
+
+    public VmOverviewPanel() {
+        super();
+        initializePanel();
+        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+
+            @Override
+            public void componentHidden(Component component) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
+    }
+
+    @Override
+    public void addActionListener(ActionListener<Action> listener) {
+        notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeActionListener(ActionListener<Action> listener) {
+        notifier.removeActionListener(listener);
+    }
+
+    @Override
+    public void setVmPid(String pid) {
+        this.pid.setText(pid);
+    }
+
+    @Override
+    public void setVmStartTimeStamp(String timeStamp) {
+        this.startTimeStamp.setText(timeStamp);
+    }
+
+    @Override
+    public void setVmStopTimeStamp(String timeStamp) {
+        this.stopTimeStamp.setText(timeStamp);
+    }
+
+    @Override
+    public void setMainClass(String mainClass) {
+        this.mainClass.setText(mainClass);
+    }
+
+    @Override
+    public void setJavaCommandLine(String javaCommandLine) {
+        this.javaCommandLine.setText(javaCommandLine);
+    }
+
+    @Override
+    public void setJavaHome(String javaHome) {
+        this.javaHome.setText(javaHome);
+
+    }
+
+    @Override
+    public void setJavaVersion(String javaVersion) {
+        this.javaVersion.setText(javaVersion);
+    }
+
+    @Override
+    public void setVmNameAndVersion(String vmNameAndVersion) {
+        this.vmNameAndVersion.setText(vmNameAndVersion);
+    }
+
+    @Override
+    public void setVmArguments(String vmArguments) {
+        this.vmArguments.setText(vmArguments);
+    }
+
+    @Override
+    public void setVmInfo(String string) {
+        // no-op
+    }
+
+    @Override
+    public Component getUiComponent() {
+        return visiblePanel;
+    }
+
+    private void initializePanel() {
+        visiblePanel = new HeaderPanel();
+
+        visiblePanel.setHeader(translator.localize(LocaleResources.VM_INFO_TITLE));
+
+        TableEntry entry;
+        List<Section> allSections = new ArrayList<Section>();
+
+        Section processSection = new Section(translator.localize(LocaleResources.VM_INFO_SECTION_PROCESS));
+        allSections.add(processSection);
+
+        entry = new TableEntry(translator.localize(LocaleResources.VM_INFO_PROCESS_ID), pid);
+        processSection.add(entry);
+        entry = new TableEntry(translator.localize(LocaleResources.VM_INFO_START_TIME), startTimeStamp);
+        processSection.add(entry);
+        entry = new TableEntry(translator.localize(LocaleResources.VM_INFO_STOP_TIME), stopTimeStamp);
+        processSection.add(entry);
+
+        Section javaSection = new Section(translator.localize(LocaleResources.VM_INFO_SECTION_JAVA));
+        allSections.add(javaSection);
+
+        entry = new TableEntry(translator.localize(LocaleResources.VM_INFO_MAIN_CLASS), mainClass);
+        javaSection.add(entry);
+        entry = new TableEntry(translator.localize(LocaleResources.VM_INFO_COMMAND_LINE), javaCommandLine);
+        javaSection.add(entry);
+        entry = new TableEntry(translator.localize(LocaleResources.VM_INFO_JAVA_VERSION), javaVersion);
+        javaSection.add(entry);
+        entry = new TableEntry(translator.localize(LocaleResources.VM_INFO_VM), vmNameAndVersion);
+        javaSection.add(entry);
+        entry = new TableEntry(translator.localize(LocaleResources.VM_INFO_VM_ARGUMENTS), vmArguments);
+        javaSection.add(entry);
+
+        SimpleTable simpleTable = new SimpleTable();
+        JPanel table = simpleTable.createTable(allSections);
+        table.setBorder(Components.smallBorder());
+        visiblePanel.setContent(table);
+    }
+}
Binary file client/swing/src/main/resources/duke.png has changed
Binary file client/swing/src/main/resources/icons/resize-grip.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/main/resources/icons/resize-grip.svg	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="13"
+   height="13"
+   id="svg17653"
+   version="1.1"
+   inkscape:version="0.48.2 r9819"
+   sodipodi:docname="resize-grip.svg">
+  <defs
+     id="defs17655" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="21.311078"
+     inkscape:cx="-8.2186936"
+     inkscape:cy="8.0008486"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:window-width="1920"
+     inkscape:window-height="1022"
+     inkscape:window-x="0"
+     inkscape:window-y="26"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata17658">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(0,-3)">
+    <path
+       transform="matrix(0.65777374,0,0,0.65777374,-560.57081,-392.19484)"
+       d="m 870.53682,617.14966 a 1.9003495,1.9003495 0 1 1 -3.80069,0 1.9003495,1.9003495 0 1 1 3.80069,0 z"
+       sodipodi:ry="1.9003495"
+       sodipodi:rx="1.9003495"
+       sodipodi:cy="617.14966"
+       sodipodi:cx="868.63647"
+       id="path5513"
+       style="fill:#b9beb3;fill-opacity:1;stroke:none;display:inline;enable-background:new"
+       sodipodi:type="arc" />
+    <path
+       sodipodi:type="arc"
+       style="fill:#b9beb3;fill-opacity:1;stroke:none;display:inline;enable-background:new"
+       id="path5515"
+       sodipodi:cx="868.63647"
+       sodipodi:cy="617.14966"
+       sodipodi:rx="1.9003495"
+       sodipodi:ry="1.9003495"
+       d="m 870.53682,617.14966 a 1.9003495,1.9003495 0 1 1 -3.80069,0 1.9003495,1.9003495 0 1 1 3.80069,0 z"
+       transform="matrix(0.65777374,0,0,0.65777374,-563.84354,-392.19484)" />
+    <path
+       sodipodi:type="arc"
+       style="fill:#b9beb3;fill-opacity:1;stroke:none;display:inline;enable-background:new"
+       id="path5517"
+       sodipodi:cx="868.63647"
+       sodipodi:cy="617.14966"
+       sodipodi:rx="1.9003495"
+       sodipodi:ry="1.9003495"
+       d="m 870.53682,617.14966 a 1.9003495,1.9003495 0 1 1 -3.80069,0 1.9003495,1.9003495 0 1 1 3.80069,0 z"
+       transform="matrix(0.65777374,0,0,0.65777374,-560.57081,-395.46756)" />
+    <path
+       transform="matrix(0.65777374,0,0,0.65777374,-560.57081,-398.74029)"
+       d="m 870.53682,617.14966 a 1.9003495,1.9003495 0 1 1 -3.80069,0 1.9003495,1.9003495 0 1 1 3.80069,0 z"
+       sodipodi:ry="1.9003495"
+       sodipodi:rx="1.9003495"
+       sodipodi:cy="617.14966"
+       sodipodi:cx="868.63647"
+       id="path5519"
+       style="fill:#b9beb3;fill-opacity:1;stroke:none;display:inline;enable-background:new"
+       sodipodi:type="arc" />
+    <path
+       transform="matrix(0.65777374,0,0,0.65777374,-567.11626,-392.19484)"
+       d="m 870.53682,617.14966 a 1.9003495,1.9003495 0 1 1 -3.80069,0 1.9003495,1.9003495 0 1 1 3.80069,0 z"
+       sodipodi:ry="1.9003495"
+       sodipodi:rx="1.9003495"
+       sodipodi:cy="617.14966"
+       sodipodi:cx="868.63647"
+       id="path5521"
+       style="fill:#b9beb3;fill-opacity:1;stroke:none;display:inline;enable-background:new"
+       sodipodi:type="arc" />
+    <path
+       transform="matrix(0.65777374,0,0,0.65777374,-563.84354,-395.46756)"
+       d="m 870.53682,617.14966 a 1.9003495,1.9003495 0 1 1 -3.80069,0 1.9003495,1.9003495 0 1 1 3.80069,0 z"
+       sodipodi:ry="1.9003495"
+       sodipodi:rx="1.9003495"
+       sodipodi:cy="617.14966"
+       sodipodi:cx="868.63647"
+       id="path5523"
+       style="fill:#b9beb3;fill-opacity:1;stroke:none;display:inline;enable-background:new"
+       sodipodi:type="arc" />
+  </g>
+</svg>
Binary file client/swing/src/main/resources/icons/scale-slider-vert-backdrop.png has changed
Binary file client/swing/src/main/resources/icons/scale-slider-vert.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/IconDescriptorTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,98 @@
+/*
+ * 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.swing;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.client.ui.IconDescriptor;
+
+public class IconDescriptorTest {
+
+    @Test
+    public void test() throws IOException {
+        ClassLoader classLoader = IconResource.class.getClassLoader();
+        String resource = IconResource.JAVA_APPLICATION.getPath();
+        IconDescriptor descriptor = IconDescriptor.createFromClassloader(classLoader, resource);
+        ByteBuffer buffer = descriptor.getData();
+        
+        assertEquals(3512, buffer.capacity());
+        
+        byte[] data = buffer.array();
+        
+        // the first four bytes should be .PNG
+        int current = ((int) data[0]) & 0xFF;
+        assertEquals(0x89, current);
+        
+        current = ((int) data[1]) & 0xFF;
+        assertEquals(0x50, current);
+        
+        current = ((int) data[2]) & 0xFF;
+        assertEquals(0x4E, current);
+        
+        current = ((int) data[3]) & 0xFF;
+        assertEquals(0x47, current);
+        
+        // check IHDR chunk
+        current = ((int) data[12]) & 0xFF;
+        assertEquals(0x49, current);
+        
+        current = ((int) data[12]) & 0xFF;
+        assertEquals(0x49, current);
+        
+        current = ((int) data[13]) & 0xFF;
+        assertEquals(0x48, current);
+        
+        current = ((int) data[14]) & 0xFF;
+        assertEquals(0x44, current);
+        
+        current = ((int) data[15]) & 0xFF;
+        assertEquals(0x52, current);
+        
+        // get width and height, 4 bytes each, the icon is 16x16
+        current = ((int) data[16]) << 24 | ((int) data[17]) << 16 | ((int) data[18]) << 8 | (((int) data[19]) & 0xFF);
+        assertEquals(16, current);
+        
+        current = ((int) data[20]) << 24 | ((int) data[21]) << 16 | ((int) data[22]) << 8 | (((int) data[23]) & 0xFF);
+        assertEquals(16, current);
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/MainWindowTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,354 @@
+/*
+ * 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.swing;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.atLeastOnce;
+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.Collection;
+import java.util.List;
+
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JRadioButtonMenuItem;
+
+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.exception.ComponentLookupException;
+import org.fest.swing.fixture.FrameFixture;
+import org.fest.swing.fixture.JMenuItemFixture;
+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.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import com.redhat.thermostat.client.core.HostFilter;
+import com.redhat.thermostat.client.core.views.SearchFieldView;
+import com.redhat.thermostat.client.osgi.service.HostDecorator;
+import com.redhat.thermostat.client.osgi.service.MenuAction;
+import com.redhat.thermostat.client.swing.internal.MainView;
+import com.redhat.thermostat.client.ui.Decorator;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.HostsVMsLoader;
+import com.redhat.thermostat.common.dao.HostRef;
+
+@RunWith(CacioFESTRunner.class)
+public class MainWindowTest {
+
+    private FrameFixture frameFixture;
+    private MainWindow window;
+    private ActionListener<MainView.Action> l;
+
+    @BeforeClass
+    public static void setUpOnce() {
+        FailOnThreadViolationRepaintManager.install();
+    }
+
+    @SuppressWarnings("unchecked") // mock(ActionListener.class)
+    @Before
+    public void setUp() {
+
+        GuiActionRunner.execute(new GuiTask() {
+            
+            @Override
+            protected void executeInEDT() throws Throwable {
+                window = new MainWindow();
+                l = mock(ActionListener.class);
+                window.addActionListener(l);
+            }
+        });
+
+        frameFixture = new FrameFixture(window);
+    }
+
+    @After
+    public void tearDown() {
+        frameFixture.cleanUp();
+        frameFixture = null;
+        window = null;
+        l = null;
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void testHostVmSelectionChangedSupport() {
+        frameFixture.show();
+        JTreeFixture hostVMTree = frameFixture.tree("agentVmTree");
+        hostVMTree.selectRows(0);
+
+        verify(l).actionPerformed(new ActionEvent<MainView.Action>(window, MainView.Action.HOST_VM_SELECTION_CHANGED));
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void testHostVmDecoratorsAdded() throws InterruptedException {
+        
+        List<HostDecorator> decorators = new ArrayList<>();
+        HostDecorator refDecorator = mock(HostDecorator.class);
+        final Decorator decorator = mock(Decorator.class);
+        when(decorator.getLabel(anyString())).thenReturn("fluff");
+        
+        when(refDecorator.getDecorator()).thenReturn(decorator);
+        
+        HostFilter filter = mock(HostFilter.class);
+        when(filter.matches(isA(HostRef.class))).thenReturn(false).thenReturn(true);
+
+        when(refDecorator.getFilter()).thenReturn(filter);
+        
+        decorators.add(refDecorator);
+        
+        HostsVMsLoader hostsVMsLoader = mock(HostsVMsLoader.class);
+        Collection<HostRef> expectedHosts = new ArrayList<>();
+        expectedHosts.add(new HostRef("123", "fluffhost1"));
+        expectedHosts.add(new HostRef("456", "fluffhost2"));
+        
+        when(hostsVMsLoader.getHosts()).thenReturn(expectedHosts);
+        
+        window.updateTree(null, null, decorators, null, hostsVMsLoader);
+
+        Thread.sleep(50);
+        
+        frameFixture.show();
+        frameFixture.requireVisible();
+        
+        verify(decorator, times(0)).getLabel("fluffhost1");
+        verify(decorator, atLeastOnce()).getLabel("fluffhost2");
+    }
+    
+    @Category(GUITest.class)
+    @Test
+    public void testHostVMTreeFilterPropertySupport() {
+        String SEARCH_TEXT = "test";
+        frameFixture.show();
+        JTextComponentFixture hostVMTreeFilterField = frameFixture.textBox(SearchFieldView.VIEW_NAME);
+        hostVMTreeFilterField.enterText(SEARCH_TEXT);
+
+        verify(l, times(SEARCH_TEXT.length())).actionPerformed(new ActionEvent<MainView.Action>(window, MainView.Action.HOST_VM_TREE_FILTER));
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void verifyThatCloseFiresShutdownEvent() {
+
+        frameFixture.show();
+
+        frameFixture.close();
+        frameFixture.requireNotVisible();
+        verify(l).actionPerformed(new ActionEvent<MainView.Action>(window, MainView.Action.SHUTDOWN));
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void verifyShowMainWindowShowsWindow() {
+        window.showMainWindow();
+        frameFixture.requireVisible();
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void verifyHideMainWindowHidesWindow() {
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                window.showMainWindow();
+            }
+        });
+        frameFixture.requireVisible();
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                window.hideMainWindow();
+            }
+        });
+        frameFixture.requireNotVisible();
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void verifyThatClientPreferencesMenuItemTriggersEvent() {
+        frameFixture.show();
+        JMenuItemFixture menuItem = frameFixture.menuItem("showClientConfig");
+        menuItem.click();
+        frameFixture.close();
+        frameFixture.requireNotVisible();
+
+        verify(l).actionPerformed(new ActionEvent<MainView.Action>(window, MainView.Action.SHOW_CLIENT_CONFIG));
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void verifyThatAgentPreferencesMenuItemTriggersEvent() {
+        frameFixture.show();
+        JMenuItemFixture menuItem = frameFixture.menuItem("showAgentConfig");
+        menuItem.click();
+        frameFixture.close();
+        frameFixture.requireNotVisible();
+
+        verify(l).actionPerformed(new ActionEvent<MainView.Action>(window, MainView.Action.SHOW_AGENT_CONFIG));
+    }
+
+
+    @Category(GUITest.class)
+    @Test
+    public void verifyThatHistorySwitchTriggersEvent() {
+        frameFixture.show();
+        JMenuItemFixture menuItem = frameFixture.menuItem("historyModeSwitch");
+        menuItem.click();
+        frameFixture.close();
+        frameFixture.requireNotVisible();
+
+        verify(l).actionPerformed(new ActionEvent<MainView.Action>(window, MainView.Action.SWITCH_HISTORY_MODE));
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void addRemoveMenu() {
+    	final String PARENT_NAME = "File";
+        final String MENU_NAME = "Test2";
+        MenuAction action = mock(MenuAction.class);
+        when(action.getName()).thenReturn(MENU_NAME);
+        when(action.getPath()).thenReturn(new String[] {PARENT_NAME, MENU_NAME});
+        when(action.getType()).thenReturn(MenuAction.Type.STANDARD);
+
+        JMenuItemFixture menuItem;
+
+        frameFixture.show();
+
+        window.addMenu(action);
+
+        menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
+        assertNotNull(menuItem);
+        menuItem.click();
+
+        verify(action).execute();
+
+        window.removeMenu(action);
+
+        try {
+            menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
+            // should not reach here
+            assertTrue(false);
+        } catch (ComponentLookupException cle) {
+            // expected
+        }
+    }
+    
+    @Category(GUITest.class)
+    @Test
+    public void addRadioMenu() {
+    	final String PARENT_NAME = "File";
+        final String MENU_NAME = "Test";
+        MenuAction action = mock(MenuAction.class);
+        when(action.getName()).thenReturn(MENU_NAME);
+        when(action.getPath()).thenReturn(new String[] {PARENT_NAME, MENU_NAME});
+
+
+        when(action.getType()).thenReturn(MenuAction.Type.RADIO);
+
+        JMenuItemFixture menuItem;
+
+        frameFixture.show();
+
+        window.addMenu(action);
+
+        menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
+        assertNotNull(menuItem);
+
+        assertTrue(menuItem.target instanceof JRadioButtonMenuItem);
+    }
+    
+    @Category(GUITest.class)
+    @Test
+    public void addCheckBoxMenu() {
+    	final String PARENT_NAME = "File";
+        final String MENU_NAME = "Test";
+        MenuAction action = mock(MenuAction.class);
+        when(action.getName()).thenReturn(MENU_NAME);
+        when(action.getType()).thenReturn(MenuAction.Type.CHECK);
+        when(action.getPath()).thenReturn(new String[] {PARENT_NAME, MENU_NAME});
+
+
+        JMenuItemFixture menuItem;
+
+        frameFixture.show();
+
+        window.addMenu(action);
+
+        menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
+        assertNotNull(menuItem);
+
+        assertTrue(menuItem.target instanceof JCheckBoxMenuItem);
+    }
+    
+    @Category(GUITest.class)
+    @Test
+    public void testGetHostVMTreeFilter() {
+        frameFixture.show();
+        JTextComponentFixture hostVMTreeFilterField = frameFixture.textBox(SearchFieldView.VIEW_NAME);
+        hostVMTreeFilterField.enterText("test");
+        String actual = window.getHostVmTreeFilterText();
+        assertEquals("test", actual);
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void testGetSelectedHostOrVm() {
+        frameFixture.show();
+        JTreeFixture hostVMTree = frameFixture.tree("agentVmTree");
+        hostVMTree.selectRow(0);
+
+        assertEquals(null, window.getSelectedHostOrVm());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/MenuHelperTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JRadioButtonMenuItem;
+
+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.exception.ComponentLookupException;
+import org.fest.swing.fixture.FrameFixture;
+import org.fest.swing.fixture.JMenuItemFixture;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import com.redhat.thermostat.client.osgi.service.MenuAction;
+
+@RunWith(CacioFESTRunner.class)
+public class MenuHelperTest {
+
+    private FrameFixture frameFixture;
+    private JFrame window;
+    private MenuHelper menu;
+
+    @BeforeClass
+    public static void setUpOnce() {
+        FailOnThreadViolationRepaintManager.install();
+    }
+
+    @Before
+    public void setUp() {
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                window = new JFrame();
+                JMenuBar menuBar = new JMenuBar();
+                window.setJMenuBar(menuBar);
+                JMenu fileMenu = new JMenu("File");
+                fileMenu.setName("File");
+                menuBar.add(fileMenu);
+                menu = new MenuHelper(menuBar);
+                window.pack();
+            }
+        });
+
+        frameFixture = new FrameFixture(window);
+    }
+
+    @After
+    public void tearDown() {
+        frameFixture.cleanUp();
+        frameFixture = null;
+        window = null;
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void addRemoveWithNewTopLevelMenu() {
+        final String PARENT_NAME = "Test1";
+        final String MENU_NAME = "Test2";
+        MenuAction action = mock(MenuAction.class);
+        when(action.getName()).thenReturn(MENU_NAME);
+        when(action.getPath()).thenReturn(new String[] { PARENT_NAME, MENU_NAME });
+        when(action.getType()).thenReturn(MenuAction.Type.STANDARD);
+
+        JMenuItemFixture menuItem;
+
+        frameFixture.show();
+
+        menu.addMenuAction(action);
+
+        menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
+        assertNotNull(menuItem);
+
+        menu.removeMenuAction(action);
+
+        try {
+            menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
+            // should not reach here
+            assertTrue(false);
+        } catch (ComponentLookupException cle) {
+            // expected
+        }
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void addRemoveToExistingMenu() {
+        final String PARENT_NAME = "File";
+        final String MENU_NAME = "Test2";
+        MenuAction action = mock(MenuAction.class);
+        when(action.getName()).thenReturn(MENU_NAME);
+        when(action.getPath()).thenReturn(new String[] { PARENT_NAME, MENU_NAME });
+        when(action.getType()).thenReturn(MenuAction.Type.STANDARD);
+
+        JMenuItemFixture menuItem;
+
+        frameFixture.show();
+
+        assertNotNull(frameFixture.menuItem("File"));
+
+        menu.addMenuAction(action);
+
+        menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
+        assertNotNull(menuItem);
+
+        menu.removeMenuAction(action);
+
+        try {
+            menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
+            // should not reach here
+            assertTrue(false);
+        } catch (ComponentLookupException cle) {
+            // expected
+        }
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void addRemoveHighlyNextedMenu() {
+        final String[] path = new String[] { "View", "Filter", "Virtual Machine", "Show Only Running" };
+        MenuAction action = mock(MenuAction.class);
+        when(action.getName()).thenReturn(path[path.length - 1]);
+        when(action.getPath()).thenReturn(path);
+        when(action.getType()).thenReturn(MenuAction.Type.STANDARD);
+
+        JMenuItemFixture menuItem;
+
+        frameFixture.show();
+
+        menu.addMenuAction(action);
+
+        menuItem = frameFixture.menuItemWithPath(path);
+        assertNotNull(menuItem);
+
+        menu.removeMenuAction(action);
+
+        try {
+            menuItem = frameFixture.menuItemWithPath(path);
+            // should not reach here
+            assertTrue(false);
+        } catch (ComponentLookupException cle) {
+            // expected
+        }
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void addRadioMenu() {
+        final String PARENT_NAME = "File";
+        final String MENU_NAME = "Test";
+        MenuAction action = mock(MenuAction.class);
+        when(action.getName()).thenReturn(MENU_NAME);
+        when(action.getPath()).thenReturn(new String[] { PARENT_NAME, MENU_NAME });
+        when(action.getType()).thenReturn(MenuAction.Type.RADIO);
+
+        JMenuItemFixture menuItem;
+
+        frameFixture.show();
+
+        menu.addMenuAction(action);
+
+        menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
+        assertNotNull(menuItem);
+
+        assertTrue(menuItem.target instanceof JRadioButtonMenuItem);
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void addCheckBoxMenu() {
+        final String PARENT_NAME = "File";
+        final String MENU_NAME = "Test";
+        MenuAction action = mock(MenuAction.class);
+        when(action.getName()).thenReturn(MENU_NAME);
+        when(action.getType()).thenReturn(MenuAction.Type.CHECK);
+        when(action.getPath()).thenReturn(new String[] { PARENT_NAME, MENU_NAME });
+
+        JMenuItemFixture menuItem;
+
+        frameFixture.show();
+
+        menu.addMenuAction(action);
+
+        menuItem = frameFixture.menuItemWithPath(PARENT_NAME, MENU_NAME);
+        assertNotNull(menuItem);
+
+        assertTrue(menuItem.target instanceof JCheckBoxMenuItem);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/TabbedPaneMatcher.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,18 @@
+package com.redhat.thermostat.client.swing;
+
+import javax.swing.JTabbedPane;
+
+import org.fest.swing.core.GenericTypeMatcher;
+
+public class TabbedPaneMatcher extends GenericTypeMatcher<JTabbedPane> {
+
+    public TabbedPaneMatcher(Class<JTabbedPane> supportedType) {
+        super(supportedType);
+    }
+
+    @Override
+    protected boolean isMatching(JTabbedPane tab) {
+        return tab.getTabCount() > 0;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/UIResourcesTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,141 @@
+/*
+ * 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.swing;
+
+import java.awt.Color;
+import java.awt.Font;
+
+import javax.swing.LookAndFeel;
+import javax.swing.UIDefaults;
+import javax.swing.UIManager;
+import javax.swing.plaf.basic.BasicLookAndFeel;
+
+import junit.framework.Assert;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.redhat.thermostat.test.Bug;
+
+@Bug(id="976",
+     summary="About dialog creashes with GTK look and feel",
+     url="http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=976")
+public class UIResourcesTest {
+   
+    private static LookAndFeel originalLaf;
+    
+    @BeforeClass
+    public static void setUp() throws Exception {
+        final Object [] uiDefaults = new Object[] {
+            "Button.darkShadow", null,
+            "Button.focus", null,
+            "Label.font", null
+        };
+        
+        originalLaf = UIManager.getLookAndFeel();
+        UIManager.setLookAndFeel(new BasicLookAndFeel() {
+            
+            @Override
+            protected void initClassDefaults(UIDefaults table) {
+                super.initClassDefaults(table);
+                table.putDefaults(uiDefaults);
+            }
+            
+            @Override
+            protected void initSystemColorDefaults(UIDefaults table) {
+                super.initSystemColorDefaults(table);
+                table.putDefaults(uiDefaults);
+            }
+            
+            @Override
+            protected void initComponentDefaults(UIDefaults table) {
+                super.initComponentDefaults(table);
+                table.putDefaults(uiDefaults);
+            }
+            
+            @Override
+            public boolean isSupportedLookAndFeel() {
+                return true;
+            }
+            
+            @Override
+            public boolean isNativeLookAndFeel() {
+                return false;
+            }
+            
+            @Override
+            public String getName() {
+                return "fluff";
+            }
+            
+            @Override
+            public String getID() {
+                return "fluff";
+            }
+            
+            @Override
+            public String getDescription() {
+                return "fluff";
+            }
+        });
+    }
+    
+    @Test
+    public void testHyperlinkColor() {
+        Assert.assertEquals(Color.BLUE, UIResources.getInstance().hyperlinkColor());
+    }
+
+    @Test
+    public void testHyperlinkActiveColor() {
+        Assert.assertEquals(Color.BLUE, UIResources.getInstance().hyperlinkActiveColor());
+    }
+
+    @Test
+    public void testStandardFont() {
+        Assert.assertEquals(Font.DIALOG, UIResources.getInstance().standardFont().getName());
+    }
+    
+    @AfterClass
+    public static void tearDown() throws Exception {
+        if (originalLaf != null) {
+            UIManager.setLookAndFeel(originalLaf);
+        } else {
+            UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/EdtHelperTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,194 @@
+/*
+ * 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.swing.components;
+
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.awt.EventQueue;
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.Callable;
+
+import javax.swing.SwingUtilities;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class EdtHelperTest {
+
+    private class ExceptionCallable implements Callable<Object>  {
+
+        @Override
+        public Object call() throws Exception {
+            throw new Exception("fluff");
+        }
+        
+    }
+
+    private class ResultCallable implements Callable<Object> {
+    
+        private Object result;
+        private ResultCallable(Object r) {
+            result = r;
+        }
+        @Override
+        public Object call() throws Exception {
+            // By waiting here, we make sure the EDTHelper actually waits for the call.
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+            if (EventQueue.isDispatchThread()) {
+                calledOnEDT = true;
+            }
+            return result;
+        }
+        
+    }
+
+    private class TestRunnable implements Runnable {
+
+        @Override
+        public void run() {
+            // By waiting here, we make sure the EDTHelper actually waits for the call.
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+            }
+            if (EventQueue.isDispatchThread()) {
+                calledOnEDT = true;
+            }
+        }
+        
+    }
+
+    private volatile boolean calledOnEDT;
+
+    @Before
+    public void setUp() {
+        calledOnEDT = false;
+    }
+
+    @After
+    public void tearDown() {
+        calledOnEDT = false;
+    }
+
+    @Test
+    public void testCallRunnableFromNonEDT() throws InvocationTargetException, InterruptedException {
+        Runnable r = new TestRunnable();
+        new EdtHelper().callAndWait(r);
+        assertTrue(calledOnEDT);
+    }
+
+    @Test
+    public void testCallRunnableFromEDT() throws InvocationTargetException, InterruptedException {
+        final Runnable r = new TestRunnable();
+        SwingUtilities.invokeAndWait(new Runnable() {
+            
+            @Override
+            public void run() {
+                try {
+                    new EdtHelper().callAndWait(r);
+                } catch (InvocationTargetException e) {
+                    throw new RuntimeException(e);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                }
+            }
+        });
+        assertTrue(calledOnEDT);
+    }
+
+    @Test
+    public void testCallCallableFromNoEDT() throws InvocationTargetException, InterruptedException {
+        final Object expected = new Object();
+        Callable<Object> c = new ResultCallable(expected);
+        Object result = new EdtHelper().callAndWait(c);
+        assertTrue(calledOnEDT);
+        assertSame(expected, result);
+    }
+
+    @Test
+    public void testCallCallableFromEDT() throws InvocationTargetException, InterruptedException {
+        final Object expected = new Object();
+        final Callable<Object> c = new ResultCallable(expected);
+        final Object[] result = new Object[1];
+        SwingUtilities.invokeAndWait(new Runnable() {
+            
+            @Override
+            public void run() {
+                try {
+                    result[0] = new EdtHelper().callAndWait(c);
+                } catch (InvocationTargetException | InterruptedException e) {
+                    throw new RuntimeException();
+                }
+            }
+        });
+        assertTrue(calledOnEDT);
+        assertSame(expected, result[0]);
+    }
+
+    @Test(expected=InvocationTargetException.class)
+    public void testCallCallableFromNoEDTThrowingException() throws InvocationTargetException, InterruptedException {
+        Callable<Object> c = new ExceptionCallable();
+        new EdtHelper().callAndWait(c);
+    }
+
+    @Test
+    public void testCallCallableFromEDTThrowingException() throws InvocationTargetException, InterruptedException {
+        final boolean[] exceptionThrown = new boolean[1];
+        final Callable<Object> c = new ExceptionCallable();
+        SwingUtilities.invokeAndWait(new Runnable() {
+            
+            @Override
+            public void run() {
+                try {
+                    new EdtHelper().callAndWait(c);
+                } catch (InvocationTargetException e) {
+                    exceptionThrown[0] = true;
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                }
+            }
+        });
+        assertTrue(exceptionThrown[0]);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/HeaderPanelTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,184 @@
+/*
+ * 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.swing.components;
+
+import java.awt.Dimension;
+import java.util.Random;
+import java.util.prefs.BackingStoreException;
+import java.util.prefs.Preferences;
+
+import javax.swing.Icon;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+
+import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
+
+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.JPanelFixture;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+@RunWith(CacioFESTRunner.class)
+public class HeaderPanelTest {
+
+    private JFrame frame;
+    private FrameFixture frameFixture;
+    private HeaderPanel header;
+    
+    private Icon someIcon1;
+    private Icon someIcon2;
+    private Icon someIcon3;
+
+    private Preferences prefs;
+    
+    @BeforeClass
+    public static void setUpOnce() {
+        FailOnThreadViolationRepaintManager.install();
+    }
+    
+    @Before
+    public void setUp() {
+        
+        Random random = new Random(); 
+        prefs = Preferences.userRoot().node(HeaderPanelTest.class.getName() + "." + random.nextInt());
+        
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                frame = new JFrame();
+                
+                header = new HeaderPanel(prefs, "Test Panel");
+                header.setName("headerPanel");
+                
+                JPanel content = new JPanel();
+                content.setName("contentPanel");
+                
+                header.setContent(content);
+                
+                someIcon1 = new EmptyIcon(16, 16);
+                someIcon2 = new EmptyIcon(16, 16);
+                someIcon3 = new EmptyIcon(16, 16);
+                
+                ActionButton button1 = new ActionButton(someIcon1, "button1");
+                button1.setName("button1");
+                
+                ActionButton button2 = new ActionButton(someIcon2, "button2");
+                button2.setName("button2");
+                
+                ActionToggleButton toggle1 = new ActionToggleButton(someIcon3, "toggle1");
+                toggle1.setName("toggle1");
+
+                header.addToolBarButton(button1);
+                header.addToolBarButton(button2);
+                header.addToolBarButton(toggle1);
+                
+                frame.getContentPane().add(header);
+                
+                frame.setMinimumSize(new Dimension(800, 300));
+            }
+        });
+        frameFixture = new FrameFixture(frame);
+    }
+    
+    @After
+    public void tearDown() throws BackingStoreException {
+        frameFixture.cleanUp();
+        frameFixture = null;
+        prefs.removeNode();
+    }
+    
+    @Test
+    public void testContentPaneAdded() {
+        frameFixture.show();
+        
+        JPanelFixture contentPanel = frameFixture.panel("contentPanel");
+        contentPanel.requireVisible();
+    }
+    
+    @Test
+    public void testContentAdded() {
+        frameFixture.show();
+        
+        JPanelFixture contentPanel = frameFixture.panel("contentPanel");
+        contentPanel.requireVisible();
+        
+        frameFixture.button("button1").requireVisible();
+        frameFixture.button("button2").requireVisible();
+        frameFixture.toggleButton("toggle1").requireVisible();
+    }
+    
+    @Test
+    public void testshowtoolbarText() throws InterruptedException {
+        frameFixture.show();
+        
+        JPanelFixture headerPanel = frameFixture.panel("clickableArea");
+        headerPanel.requireVisible();
+        
+        assertFalse(header.isShowToolbarText());
+
+        frameFixture.button("button1").requireText("");
+
+        headerPanel.showPopupMenu().click();
+
+        assertTrue(header.isShowToolbarText());
+
+        frameFixture.button("button1").requireVisible();
+        frameFixture.button("button2").requireVisible();
+        frameFixture.toggleButton("toggle1").requireVisible();
+        
+        frameFixture.button("button1").requireText("button1");
+        
+        headerPanel.showPopupMenu().click();
+        
+        assertFalse(header.isShowToolbarText());
+
+        frameFixture.button("button1").requireText("");
+
+        frameFixture.button("button1").requireVisible();
+        frameFixture.button("button2").requireVisible();
+        frameFixture.toggleButton("toggle1").requireVisible();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/StatusBarTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.components;
+
+import static org.junit.Assert.*;
+
+import java.awt.BorderLayout;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.concurrent.Semaphore;
+
+import javax.swing.JFrame;
+
+import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
+
+import org.fest.swing.annotation.GUITest;
+import org.fest.swing.annotation.RunsInEDT;
+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.JLabelFixture;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(CacioFESTRunner.class)
+public class StatusBarTest {
+
+    private JFrame frame;
+    private FrameFixture frameFixture;
+    
+    private StatusBar statusBar;
+    
+    @BeforeClass
+    public static void setUpOnce() {
+        FailOnThreadViolationRepaintManager.install();
+    }
+    
+    @Before
+    public void setUp() {
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                frame = new JFrame();
+                frame.getContentPane().setLayout(new BorderLayout());
+                
+                statusBar = new StatusBar();
+                frame.getContentPane().add(statusBar, BorderLayout.SOUTH);
+                
+                frame.setSize(500, 500);
+            }
+        });
+        frameFixture = new FrameFixture(frame);
+    }
+    
+    @After
+    public void tearDown() {
+        frameFixture.cleanUp();
+        frameFixture = null;
+    }
+    
+    @Test
+    @GUITest
+    @RunsInEDT
+    public void testSetPrimaryStatusLabel() throws InterruptedException {
+        frameFixture.show();
+        
+        JLabelFixture labelfixture = frameFixture.label("primaryStatusLabel");
+        labelfixture.requireText("");
+        
+        final Semaphore sem = new Semaphore(0);
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                statusBar.setPrimaryStatus("test");
+                sem.release();
+            }
+        });
+        sem.acquire();
+        
+        // the label has an extra space at the beginning
+        labelfixture.requireText(" test");
+    }
+    
+    @Test
+    @GUITest
+    @RunsInEDT
+    public void testSetPrimaryStatusLabelWithProperty() throws InterruptedException {
+        frameFixture.show();
+        
+        final String[] primaryStatus = new String[2];
+        
+        final Semaphore sem = new Semaphore(2);
+        statusBar.addPropertyChangeListener(StatusBar.PRIMARY_STATUS_PROPERTY,
+                                                      new PropertyChangeListener()
+        {
+            @Override
+            public void propertyChange(PropertyChangeEvent evt) {
+                primaryStatus[0] = (String) evt.getOldValue();
+                primaryStatus[1] = (String) evt.getNewValue();
+                sem.release();
+            }
+        });
+        
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                statusBar.setPrimaryStatus("test");
+                sem.release();
+            }
+        });
+        sem.acquire(2);
+        
+        assertEquals("", primaryStatus[0]);
+        assertEquals("test", primaryStatus[1]);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/models/LongRangeNormalizerTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,120 @@
+/*
+ * 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.swing.components.models;
+
+import static org.junit.Assert.*;
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+public class LongRangeNormalizerTest {
+
+    @Test
+    public void testSameRange() {
+        
+        LongRange range = new LongRange();
+        range.setMax(10);
+        range.setMin(0);
+        
+        LongRangeNormalizer model = new LongRangeNormalizer(range);
+        
+        model.setValue(5);
+        
+        model.setMaxNormalized(10);
+        model.setMinNormalized(0);
+        
+        
+        Assert.assertEquals((int) model.getValue(), model.getValueNormalized());
+    }
+
+    @Test
+    public void testDoubleRange() {
+        
+        LongRange range = new LongRange();
+        range.setMax(10);
+        range.setMin(0);
+        
+        LongRangeNormalizer model = new LongRangeNormalizer(range);
+        
+        model.setValue(5);
+        
+        model.setMaxNormalized(20);
+        model.setMinNormalized(0);
+        
+        
+        Assert.assertEquals(10, model.getValueNormalized());
+    }
+    
+    @Test
+    public void testRanges() {
+        
+        LongRange range = new LongRange();
+        range.setMax(10);
+        range.setMin(0);
+        
+        LongRangeNormalizer model = new LongRangeNormalizer(range);
+        
+        model.setValue(5);
+        
+        model.setMaxNormalized(40);
+        model.setMinNormalized(0);
+                
+        Assert.assertEquals(20, model.getValueNormalized());
+        
+        model.setMaxNormalized(60);
+        model.setMinNormalized(0);
+                
+        Assert.assertEquals(30, model.getValueNormalized());
+                
+        model.setMaxNormalized(200);
+        model.setMinNormalized(100);
+                
+        Assert.assertEquals(150, model.getValueNormalized());
+        
+        range.setMax(100);
+        range.setMin(0);
+        model.setValue(50);
+        
+        model.setMaxNormalized(1);
+        model.setMinNormalized(0);
+                
+        Assert.assertEquals(1, model.getValueNormalized());
+        
+        model.setValue(49);
+        Assert.assertEquals(0, model.getValueNormalized());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/models/NullSelectionModelTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,112 @@
+/*
+ * 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.swing.components.models;
+
+import static org.junit.Assert.*;
+
+import javax.swing.DefaultListModel;
+import javax.swing.JFrame;
+import javax.swing.JList;
+
+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.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(CacioFESTRunner.class)
+public class NullSelectionModelTest {
+
+    private JFrame frame;
+    private FrameFixture frameFixture;
+    private JList<String> list;
+    
+    @BeforeClass
+    public static void setUpOnce() {
+        FailOnThreadViolationRepaintManager.install();
+    }
+    
+    @Before
+    public void setUp() {
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                frame = new JFrame();
+                
+                DefaultListModel<String> model = new DefaultListModel<>();
+                
+                model.addElement("fluff #1");
+                model.addElement("fluff #2");
+                model.addElement("fluff #3");
+                model.addElement("fluff #4");
+                model.addElement("fluff #5");
+
+                list = new JList<>(model);
+                list.setSelectionModel(new NullSelectionModel());
+                
+                frame.add(list);
+            }
+        });
+        frameFixture = new FrameFixture(frame);
+    }
+    
+    @After
+    public void tearDown() {
+        frameFixture.cleanUp();
+        frameFixture = null;
+    }
+    
+    @GUITest
+    @Test
+    public void testCellNotSelectable() {
+        frameFixture.show();
+        
+        String[] selection = frameFixture.list().selection();
+        assertEquals(0, selection.length);
+        frameFixture.list().clickItem(2);
+        selection = frameFixture.list().selection();
+        assertEquals(0, selection.length);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/GUIClientCommandTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,118 @@
+/*
+ * 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.swing.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Dictionary;
+
+import org.apache.commons.cli.Options;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+
+import com.redhat.thermostat.client.osgi.service.ApplicationService;
+import com.redhat.thermostat.client.osgi.service.ContextAction;
+import com.redhat.thermostat.common.cli.CommandContext;
+import com.redhat.thermostat.common.cli.CommandContextFactory;
+import com.redhat.thermostat.common.cli.CommandException;
+
+public class GUIClientCommandTest {
+
+    private GUIClientCommand cmd;
+    private Main clientMain;
+
+    @Before
+    public void setUp() {
+        clientMain = mock(Main.class);
+        cmd = new GUIClientCommand(clientMain);
+    }
+
+    @After
+    public void tearDown() {
+        cmd = null;
+        clientMain = null;
+    }
+
+    @Test
+    public void testRun() throws CommandException {
+        BundleContext bCtx = mock(BundleContext.class);
+        CommandContextFactory cmdCtxFactory = mock(CommandContextFactory.class);
+
+        CommandContext cmdCtx = mock(CommandContext.class);
+        when(cmdCtx.getCommandContextFactory()).thenReturn(cmdCtxFactory);
+
+        cmd.setBundleContext(bCtx);
+        cmd.run(cmdCtx);
+
+        verify(clientMain).run();
+        verify(bCtx).registerService(eq(ApplicationService.class.getName()), isNotNull(), any(Dictionary.class));
+        verify(bCtx).registerService(eq(ContextAction.class.getName()), isNotNull(), any(Dictionary.class));
+    }
+
+    @Test
+    public void testName() {
+        assertEquals("gui", cmd.getName());
+    }
+
+    @Test
+    public void testDescAndUsage() {
+        assertNotNull(cmd.getDescription());
+        assertNotNull(cmd.getUsage());
+    }
+
+    @Test
+    public void testRequiresStorage() {
+        assertFalse(cmd.isStorageRequired());
+    }
+
+    @Test
+    public void testOptions() {
+        Options options = cmd.getOptions();
+        assertNotNull(options);
+        assertEquals(0, options.getOptions().size());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/HostIconDecoratorTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,89 @@
+/*
+ * 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.swing.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import javax.imageio.ImageIO;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.client.core.HostFilter;
+import com.redhat.thermostat.client.ui.Decorator;
+import com.redhat.thermostat.common.dao.HostRef;
+
+public class HostIconDecoratorTest {
+
+    @Test
+    public void verifyFilter() {
+        HostIconDecorator decorator = new HostIconDecorator();
+
+        HostFilter filter = decorator.getFilter();
+        HostRef aHost = mock(HostRef.class);
+
+        assertTrue(filter.matches(aHost));
+    }
+
+    @Test
+    public void verifyHostDecoratorDoesNotModifyLabel() {
+        HostIconDecorator iconDecorator = new HostIconDecorator();
+
+        Decorator decorator = iconDecorator.getDecorator();
+
+        String INPUT = "testfoobarbaz";
+
+        assertEquals(INPUT, decorator.getLabel(INPUT));
+    }
+
+    @Test
+    public void verifyHostDecoratorHasAnIcon() throws IOException {
+        HostIconDecorator iconDecorator = new HostIconDecorator();
+
+        Decorator decorator = iconDecorator.getDecorator();
+
+        BufferedImage icon = ImageIO.read(new ByteArrayInputStream(decorator.getIconDescriptor().getData().array()));
+
+        assertNotNull(icon);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,202 @@
+/*
+ * 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.swing.internal;
+
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.concurrent.ExecutorService;
+
+import javax.swing.SwingUtilities;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import com.redhat.thermostat.client.osgi.service.ApplicationService;
+import com.redhat.thermostat.client.ui.MainWindowController;
+import com.redhat.thermostat.client.ui.UiFacadeFactory;
+import com.redhat.thermostat.common.TimerFactory;
+import com.redhat.thermostat.common.dao.DAOFactory;
+import com.redhat.thermostat.common.storage.Connection;
+import com.redhat.thermostat.common.storage.Connection.ConnectionListener;
+import com.redhat.thermostat.common.storage.Connection.ConnectionStatus;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+
+public class MainTest {
+
+    private ExecutorService executorService;
+    private OSGIUtils serviceProvider;
+
+    private MainWindowController mainWindowController;
+    private UiFacadeFactory uiFactory;
+
+    private Connection connection;
+    private ArgumentCaptor<ConnectionListener> connectionListenerCaptor;
+
+    private DAOFactory daoFactory;
+
+    private TimerFactory timerFactory;
+
+    @Before
+    public void setUp() {
+        ApplicationService appService = mock(ApplicationService.class);
+
+        executorService = mock(ExecutorService.class);
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                Runnable runnable = (Runnable) invocation.getArguments()[0];
+                runnable.run();
+                return null;
+            }
+        }).when(executorService).execute(isA(Runnable.class));
+
+        when(appService.getApplicationExecutor()).thenReturn(executorService);
+
+        serviceProvider = mock(OSGIUtils.class);
+        when(serviceProvider.getService(ApplicationService.class)).thenReturn(appService);
+
+        mainWindowController = mock(MainWindowController.class);
+
+        uiFactory = mock(UiFacadeFactory.class);
+        when(uiFactory.getMainWindow()).thenReturn(mainWindowController);
+
+        connection = mock(Connection.class);
+        connectionListenerCaptor = ArgumentCaptor.forClass(ConnectionListener.class);
+        doNothing().when(connection).addListener(connectionListenerCaptor.capture());
+
+        daoFactory = mock(DAOFactory.class);
+        when(daoFactory.getConnection()).thenReturn(connection);
+
+        timerFactory = mock(TimerFactory.class);
+    }
+
+    /**
+     * Handle all outstanding EDT events by posting a no-op event and waiting
+     * until it completes.
+     */
+    private void handleAllEdtEvents() throws Exception {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                /* NO-OP */
+            }
+        });
+    }
+
+    @Test
+    public void verifyRunWaitsForShutdown() throws Exception {
+        Main main = new Main(serviceProvider, uiFactory, daoFactory, timerFactory);
+
+        main.run();
+
+        handleAllEdtEvents();
+
+        verify(uiFactory).awaitShutdown();
+    }
+
+    @Test
+    public void verifyConnectionIsMade() throws Exception {
+        Main main = new Main(serviceProvider, uiFactory, daoFactory, timerFactory);
+
+        main.run();
+
+        handleAllEdtEvents();
+
+        verify(connection).connect();
+
+    }
+
+    @Test
+    public void verifySuccessfulConnectionTriggersMainWindowToBeShown() throws Exception {
+        Main main = new Main(serviceProvider, uiFactory, daoFactory, timerFactory);
+
+        main.run();
+
+        handleAllEdtEvents();
+
+        ConnectionListener connectionListener = connectionListenerCaptor.getValue();
+        connectionListener.changed(ConnectionStatus.CONNECTED);
+
+        handleAllEdtEvents();
+
+        verify(mainWindowController).showMainMainWindow();
+    }
+
+    @Test
+    public void verifySuccessfulConnectionRegistersDAOs() throws Exception {
+
+        Main main = new Main(serviceProvider, uiFactory, daoFactory, timerFactory);
+
+        main.run();
+
+        handleAllEdtEvents();
+
+        ConnectionListener connectionListener = connectionListenerCaptor.getValue();
+        connectionListener.changed(ConnectionStatus.CONNECTED);
+
+        handleAllEdtEvents();
+
+        verify(daoFactory).registerDAOsAndStorageAsOSGiServices();
+    }
+
+    @Ignore("this prompts the user with some gui")
+    @Test
+    public void verifyFailedConnectionTriggersShutdown() throws Exception {
+
+        Main main = new Main(serviceProvider, uiFactory, daoFactory, timerFactory);
+
+        main.run();
+
+        handleAllEdtEvents();
+
+        ConnectionListener connectionListener = connectionListenerCaptor.getValue();
+        connectionListener.changed(ConnectionStatus.FAILED_TO_CONNECT);
+
+        handleAllEdtEvents();
+
+        verify(uiFactory).shutdown();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainWindowControllerImplTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,561 @@
+/*
+ * 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.swing.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.awt.event.MouseEvent;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.osgi.framework.BundleException;
+
+import com.redhat.thermostat.client.core.VmFilter;
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.osgi.service.MenuAction;
+import com.redhat.thermostat.client.osgi.service.VMContextAction;
+import com.redhat.thermostat.client.osgi.service.VmDecorator;
+import com.redhat.thermostat.client.ui.HostVmFilter;
+import com.redhat.thermostat.client.ui.SummaryController;
+import com.redhat.thermostat.client.ui.UiFacadeFactory;
+import com.redhat.thermostat.client.ui.VmInformationController;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.HostsVMsLoader;
+import com.redhat.thermostat.common.ThermostatExtensionRegistry;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.ThermostatExtensionRegistry.Action;
+import com.redhat.thermostat.common.Timer.SchedulingType;
+import com.redhat.thermostat.common.TimerFactory;
+import com.redhat.thermostat.common.appctx.ApplicationContext;
+import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
+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.model.VmInfo;
+import com.redhat.thermostat.test.Bug;
+
+public class MainWindowControllerImplTest {
+
+    private ActionListener<MainView.Action> l;
+
+    private MainWindowControllerImpl controller;
+
+    private UiFacadeFactory uiFacadeFactory;
+    
+    private MainView view;
+
+    private Timer mainWindowTimer;
+
+    private HostInfoDAO mockHostsDAO;
+    private VmInfoDAO mockVmsDAO;
+
+    private VMContextAction action1;
+    private VMContextAction action2;
+
+    private HostFilterRegistry hostFilterRegistry;
+    private VmFilterRegistry vmFilterRegistry;
+    private HostTreeDecoratorRegistry hostDecoratorRegistry;
+    private VMTreeDecoratorRegistry vmDecoratorRegistry;
+    private VMInformationRegistry vmInfoRegistry;
+    private MenuRegistry menus;
+    
+    @SuppressWarnings("unused")
+    private ActionListener<ThermostatExtensionRegistry.Action> hostFiltersListener;
+    @SuppressWarnings("unused")
+    private ActionListener<ThermostatExtensionRegistry.Action> vmFiltersListener;
+    private ActionListener<ThermostatExtensionRegistry.Action> decoratorsListener;
+    
+    @BeforeClass
+    public static void setUpOnce() {
+        // TODO remove when controller uses mocked objects rather than real swing objects
+        FailOnThreadViolationRepaintManager.install();
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" }) // ActionListener fluff
+    @Before
+    public void setUp() throws Exception {
+        ApplicationContextUtil.resetApplicationContext();
+
+        // Setup timers
+        mainWindowTimer = mock(Timer.class);
+        Timer otherTimer = mock(Timer.class); // FIXME needed for SummaryView; remove later
+        TimerFactory timerFactory = mock(TimerFactory.class);
+        when(timerFactory.createTimer()).thenReturn(mainWindowTimer).thenReturn(otherTimer);
+        ApplicationContext.getInstance().setTimerFactory(timerFactory);
+
+        SummaryController summaryController = mock(SummaryController.class);
+
+        uiFacadeFactory = mock(UiFacadeFactory.class);
+        
+        when(uiFacadeFactory.getSummary()).thenReturn(summaryController);
+
+        mockHostsDAO = mock(HostInfoDAO.class);
+        mockVmsDAO = mock(VmInfoDAO.class);
+
+        // Setup View
+        view = mock(MainView.class);
+        ArgumentCaptor<ActionListener> grabListener = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addActionListener(grabListener.capture());
+        
+        RegistryFactory registryFactory = mock(RegistryFactory.class);
+        hostFilterRegistry = mock(HostFilterRegistry.class);
+        vmFilterRegistry = mock(VmFilterRegistry.class);
+        hostDecoratorRegistry = mock(HostTreeDecoratorRegistry.class);
+        vmDecoratorRegistry = mock(VMTreeDecoratorRegistry.class);
+        vmInfoRegistry = mock(VMInformationRegistry.class);
+        menus = mock(MenuRegistry.class);
+
+        when(registryFactory.createMenuRegistry()).thenReturn(menus);
+        when(registryFactory.createHostTreeDecoratorRegistry()).thenReturn(hostDecoratorRegistry);
+        when(registryFactory.createVMTreeDecoratorRegistry()).thenReturn(vmDecoratorRegistry);
+        when(registryFactory.createHostFilterRegistry()).thenReturn(hostFilterRegistry);
+        when(registryFactory.createVmFilterRegistry()).thenReturn(vmFilterRegistry);
+        when(registryFactory.createVMInformationRegistry()).thenReturn(vmInfoRegistry);
+        
+        ArgumentCaptor<ActionListener> grabHostFiltersListener = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(hostFilterRegistry).addActionListener(grabHostFiltersListener.capture());
+
+        ArgumentCaptor<ActionListener> grabVmFiltersListener = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(vmFilterRegistry).addActionListener(grabVmFiltersListener.capture());
+
+        ArgumentCaptor<ActionListener> grabDecoratorsListener = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(vmDecoratorRegistry).addActionListener(grabDecoratorsListener.capture());
+        
+        ArgumentCaptor<ActionListener> grabInfoRegistry = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(vmInfoRegistry).addActionListener(grabInfoRegistry.capture());
+
+        setUpVMContextActions();
+
+        controller = new MainWindowControllerImpl(uiFacadeFactory, view, registryFactory, mockHostsDAO, mockVmsDAO);
+        l = grabListener.getValue();
+        
+        hostFiltersListener = grabHostFiltersListener.getValue();
+        vmFiltersListener = grabVmFiltersListener.getValue();
+        decoratorsListener = grabDecoratorsListener.getValue();
+    }
+
+    private void setUpVMContextActions() {
+        action1 = mock(VMContextAction.class);
+        VmFilter action1Filter = mock(VmFilter.class);
+        when(action1Filter.matches(isA(VmRef.class))).thenReturn(true);
+
+        when(action1.getName()).thenReturn("action1");
+        when(action1.getDescription()).thenReturn("action1desc");
+        when(action1.getFilter()).thenReturn(action1Filter);
+        
+        action2 = mock(VMContextAction.class);
+        VmFilter action2Filter = mock(VmFilter.class);
+        when(action2Filter.matches(isA(VmRef.class))).thenReturn(false);
+
+        when(action2.getName()).thenReturn("action2");
+        when(action2.getDescription()).thenReturn("action2desc");
+        when(action2.getFilter()).thenReturn(action2Filter);
+        
+        Collection<VMContextAction> actions = new ArrayList<>();
+        actions.add(action1);
+        actions.add(action2);
+        
+        when(uiFacadeFactory.getVMContextActions()).thenReturn(actions);
+    }
+
+    @After
+    public void tearDown() {
+        view = null;
+        controller = null;
+        mockHostsDAO = null;
+        mockVmsDAO = null;
+        l = null;
+        ApplicationContextUtil.resetApplicationContext();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void verifyDecoratorsAdded() {
+
+        List<VmDecorator> currentDecoratros = controller.getVmTreeDecorators();
+        assertEquals(0, currentDecoratros.size());
+        
+        ActionEvent<ThermostatExtensionRegistry.Action> event =
+                new ActionEvent<ThermostatExtensionRegistry.Action>(vmDecoratorRegistry,
+                        ThermostatExtensionRegistry.Action.SERVICE_ADDED);
+        
+        VmDecorator payload = mock(VmDecorator.class);
+        event.setPayload(payload);
+        
+        decoratorsListener.actionPerformed(event);
+
+        currentDecoratros = controller.getVmTreeDecorators();
+        assertEquals(1, currentDecoratros.size());
+        assertEquals(payload, currentDecoratros.get(0));
+        
+        verify(view).updateTree(any(List.class), isA(List.class), isA(List.class), any(List.class), any(HostsVMsLoader.class));
+    }
+    
+    @Test
+    public void verifyThatHiddenEventStopsController() {
+
+        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HIDDEN));
+
+        verify(mainWindowTimer).stop();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void verifyThatHostsVmsFilterChangeUpdatesTree() {
+
+        when(view.getHostVmTreeFilterText()).thenReturn("test");
+
+        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_TREE_FILTER));
+
+        verify(view).updateTree(isA(List.class), isA(List.class), isA(List.class), isA(List.class), isA(HostsVMsLoader.class));
+    }
+    
+    @Test
+    public void verifyTimerGetsStartedOnBecomingVisible() {
+        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.VISIBLE));
+
+        verify(mainWindowTimer).setDelay(3);
+        verify(mainWindowTimer).setTimeUnit(TimeUnit.SECONDS);
+        verify(mainWindowTimer).setSchedulingType(SchedulingType.FIXED_RATE);
+        verify(mainWindowTimer).start();
+    }
+
+    @Test
+    public void verifyShowMainWindowActuallyCallsView() {
+        controller.showMainMainWindow();
+        verify(view).showMainWindow();
+    }
+
+    @Test
+    public void verifySubViewIsSetByDefault() throws InvocationTargetException, InterruptedException {
+        verify(view).setSubView(any(BasicView.class));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void verifyUpdateHostsVMsLoadsCorrectHosts() {
+
+        Collection<HostRef> expectedHosts = new ArrayList<>();
+        expectedHosts.add(new HostRef("123", "fluffhost1"));
+        expectedHosts.add(new HostRef("456", "fluffhost2"));
+
+        when(mockHostsDAO.getAliveHosts()).thenReturn(expectedHosts);
+
+        controller.doUpdateTreeAsync();
+
+        ArgumentCaptor<HostsVMsLoader> arg = ArgumentCaptor.forClass(HostsVMsLoader.class);
+        verify(view).updateTree(isA(List.class), isA(List.class), isA(List.class), isA(List.class), arg.capture());
+        HostsVMsLoader loader = arg.getValue();
+
+        Collection<HostRef> actualHosts = loader.getHosts();
+        assertEqualCollection(expectedHosts, actualHosts);
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Test
+    public void verifyHistoryModeUpdateHostsVMCorrectly() {
+
+        Collection<HostRef> liveHost = new ArrayList<>();
+        liveHost.add(new HostRef("123", "fluffhost1"));
+        liveHost.add(new HostRef("456", "fluffhost2"));
+
+        Collection<HostRef> allHosts = new ArrayList<>();
+        allHosts.addAll(liveHost);
+        allHosts.add(new HostRef("789", "fluffhost3"));
+
+        when(mockHostsDAO.getAliveHosts()).thenReturn(liveHost);
+        when(mockHostsDAO.getHosts()).thenReturn(allHosts);
+
+        controller.doUpdateTreeAsync();
+
+        ArgumentCaptor<HostsVMsLoader> arg = ArgumentCaptor.forClass(HostsVMsLoader.class);
+        verify(view).updateTree(isA(List.class), isA(List.class), isA(List.class), isA(List.class), arg.capture());
+        HostsVMsLoader loader = arg.getValue();
+
+        Collection<HostRef> actualHosts = loader.getHosts();
+        assertEqualCollection(liveHost, actualHosts);
+
+        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.SWITCH_HISTORY_MODE));
+        ArgumentCaptor<HostsVMsLoader> argCaptor = ArgumentCaptor.forClass(HostsVMsLoader.class);
+        // actionPerformed triggers updateTree
+        verify(view, times(2)).updateTree(isA(List.class), isA(List.class), isA(List.class), isA(List.class), argCaptor.capture());
+        loader = argCaptor.getValue();
+
+        actualHosts = loader.getHosts();
+        assertEqualCollection(allHosts, actualHosts);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void verifyUpdateHostsVMsLoadsCorrectVMs() {
+
+        Collection<VmRef> expectedVMs = new ArrayList<>();
+        HostRef host = new HostRef("123", "fluffhost1");
+        expectedVMs.add(new VmRef(host, 123, "vm1"));
+        expectedVMs.add(new VmRef(host, 456, "vm2"));
+
+        when(mockVmsDAO.getVMs(any(HostRef.class))).thenReturn(expectedVMs);
+
+        controller.doUpdateTreeAsync();
+
+        ArgumentCaptor<HostsVMsLoader> arg = ArgumentCaptor.forClass(HostsVMsLoader.class);
+        verify(view).updateTree(isA(List.class), isA(List.class), isA(List.class), isA(List.class), arg.capture());
+        HostsVMsLoader loader = arg.getValue();
+
+        Collection<VmRef> actualVMs = loader.getVMs(host);
+        assertEqualCollection(expectedVMs, actualVMs);
+    }
+
+    @Test
+    public void verifyUpdateHostsVMsLoadsCorrectVMWithFilter() {
+
+        VmRef ref1 = mock(VmRef.class);
+        when(ref1.getStringID()).thenReturn("test1");
+        when(ref1.getName()).thenReturn("test1");
+        
+        VmRef ref2 = mock(VmRef.class);
+        when(ref2.getStringID()).thenReturn("test2");
+        when(ref2.getName()).thenReturn("test2");
+        
+        controller.setHostVmTreeFilter("test1");
+                
+        HostVmFilter filter = controller.getSearchFilter();
+        assertTrue(filter.matches(ref1));
+        assertFalse(filter.matches(ref2));
+    }
+    
+    private void assertEqualCollection(Collection<?> expected, Collection<?> actual) {
+        assertEquals(expected.size(), actual.size());
+        assertTrue(expected.containsAll(actual));
+    }
+
+    @Test
+    @Bug(id="954",
+         summary="Thermostat GUI client should remember my last panel selected",
+         url="http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=954")
+    public void verifyOpenSameHostVMTab() throws Exception {
+
+        VmRef vmRef = mock(VmRef.class);
+        when(vmRef.getName()).thenReturn("testvm");
+        when(vmRef.getIdString()).thenReturn("testvmid");
+        HostRef ref = mock(HostRef.class);
+        when(ref.getAgentId()).thenReturn("agentId");
+        when(vmRef.getAgent()).thenReturn(ref);
+        
+        when(view.getSelectedHostOrVm()).thenReturn(vmRef);
+
+        VmInformationController vmInformationController = mock(VmInformationController.class);
+        when(vmInformationController.getSelectedChildID()).thenReturn(3);
+        when(uiFacadeFactory.getVmController(any(VmRef.class))).thenReturn(vmInformationController);
+        when(vmInformationController.selectChildID(anyInt())).thenReturn(true);
+
+        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
+
+        ArgumentCaptor<Integer> arg = ArgumentCaptor.forClass(Integer.class);
+        verify(vmInformationController).selectChildID(arg.capture());
+        verify(vmInformationController, times(0)).getSelectedChildID();
+
+        int id = arg.getValue();
+
+        assertEquals(0, id);
+
+        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
+
+        arg = ArgumentCaptor.forClass(Integer.class);
+        verify(vmInformationController, times(1)).getSelectedChildID();
+        verify(vmInformationController, times(2)).selectChildID(arg.capture());
+        id = arg.getValue();
+
+        assertEquals(3, id);
+    }
+    
+    @Test
+    public void verifyOpenSameHostVMTab2() {
+        
+        VmRef vmRef1 = mock(VmRef.class);
+        VmRef vmRef2 = mock(VmRef.class);
+        when(view.getSelectedHostOrVm()).thenReturn(vmRef1).thenReturn(vmRef1).thenReturn(vmRef2).thenReturn(vmRef1);
+
+        when(vmRef1.getName()).thenReturn("testvm");
+        when(vmRef1.getIdString()).thenReturn("testvmid");
+        HostRef ref = mock(HostRef.class);
+        when(ref.getAgentId()).thenReturn("agentId");
+        when(vmRef1.getAgent()).thenReturn(ref);
+        
+        when(vmRef2.getName()).thenReturn("testvm");
+        when(vmRef2.getIdString()).thenReturn("testvmid");
+        when(vmRef2.getAgent()).thenReturn(ref);
+        
+        VmInformationController vmInformationController1 = mock(VmInformationController.class);
+        VmInformationController vmInformationController2 = mock(VmInformationController.class);
+        
+        when(vmInformationController1.getSelectedChildID()).thenReturn(2).thenReturn(2);
+        when(vmInformationController2.getSelectedChildID()).thenReturn(3);
+        
+        when(vmInformationController1.selectChildID(0)).thenReturn(true);
+        when(vmInformationController1.selectChildID(2)).thenReturn(true);
+        when(vmInformationController1.selectChildID(3)).thenReturn(false);
+        
+        when(vmInformationController2.selectChildID(0)).thenReturn(true);
+        when(vmInformationController2.selectChildID(2)).thenReturn(true);
+        when(vmInformationController2.selectChildID(3)).thenReturn(true);
+        
+        when(uiFacadeFactory.getVmController(any(VmRef.class))).
+                             thenReturn(vmInformationController1).
+                             thenReturn(vmInformationController2).
+                             thenReturn(vmInformationController2).
+                             thenReturn(vmInformationController1);
+
+        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
+
+        ArgumentCaptor<Integer> arg = ArgumentCaptor.forClass(Integer.class);
+        verify(vmInformationController1).selectChildID(arg.capture());
+        verify(vmInformationController1, times(0)).getSelectedChildID();
+
+        int id = arg.getValue();
+
+        assertEquals(0, id);
+
+        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
+
+        arg = ArgumentCaptor.forClass(Integer.class);
+        verify(vmInformationController1).getSelectedChildID();
+        verify(vmInformationController2, times(1)).selectChildID(arg.capture());
+        id = arg.getValue();
+
+        assertEquals(2, id);
+        
+        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
+
+        arg = ArgumentCaptor.forClass(Integer.class);
+        verify(vmInformationController2, times(1)).getSelectedChildID();
+        verify(vmInformationController2, times(2)).selectChildID(arg.capture());
+        id = arg.getValue();
+
+        assertEquals(3, id);
+        
+        l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_SELECTION_CHANGED));
+
+        arg = ArgumentCaptor.forClass(Integer.class);
+        verify(vmInformationController2, times(2)).getSelectedChildID();
+        verify(vmInformationController1, times(3)).selectChildID(arg.capture());
+        id = arg.getValue();
+
+        assertEquals(2, id);
+    }
+    
+    @Test
+    public void verityVMActionsAreShown() {
+        VmInfo vmInfo = new VmInfo(0, 1, 2, null, null, null, null, null, null, null, null, null, null, null);
+        when(mockVmsDAO.getVmInfo(isA(VmRef.class))).thenReturn(vmInfo);
+
+        VmRef ref = mock(VmRef.class);
+        when(view.getSelectedHostOrVm()).thenReturn(ref);
+
+        MouseEvent uiEvent = mock(MouseEvent.class);
+        ActionEvent<MainView.Action> viewEvent = new ActionEvent<>(view, MainView.Action.SHOW_VM_CONTEXT_MENU);
+        viewEvent.setPayload(uiEvent);
+
+        l.actionPerformed(viewEvent);
+
+        verify(view).showVMContextActions(Arrays.asList(action1), uiEvent);
+    }
+    
+    @Test
+    public void verityVMActionsAreExecuted() {
+
+        VmRef vmRef = mock(VmRef.class);
+        when(view.getSelectedHostOrVm()).thenReturn(vmRef);
+
+        ActionEvent<MainView.Action> event = new ActionEvent<>(view, MainView.Action.VM_CONTEXT_ACTION);
+        event.setPayload(action1);
+        l.actionPerformed(event);
+        
+        verify(action1, times(1)).execute(any(VmRef.class));
+        verify(action2, times(0)).execute(any(VmRef.class));
+    }
+
+    @Test
+    public void verifyMenuItems() {
+        
+        ActionListener<ThermostatExtensionRegistry.Action> menuListener = controller.getMenuListener();
+
+        MenuAction action = mock(MenuAction.class);
+        when(action.getName()).thenReturn("Test1");
+
+        ActionEvent<Action> addEvent = new ActionEvent<ThermostatExtensionRegistry.Action>(
+        		menus, ThermostatExtensionRegistry.Action.SERVICE_ADDED);
+        addEvent.setPayload(action);
+        menuListener.actionPerformed(addEvent);
+        verify(view).addMenu(action);
+
+        ActionEvent<Action> removeEvent = new ActionEvent<ThermostatExtensionRegistry.Action>(menus, ThermostatExtensionRegistry.Action.SERVICE_REMOVED);
+        removeEvent.setPayload(action);
+        menuListener.actionPerformed(removeEvent);
+        verify(view).removeMenu(action);
+    }
+
+   @Test
+   public void testOSGiFrameworkShutdown() throws BundleException {
+
+       l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.SHUTDOWN));
+
+       verify(uiFacadeFactory).shutdown();
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MenuRegistryTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.internal;
+
+import static org.junit.Assert.assertEquals;
+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 org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+import com.redhat.thermostat.client.osgi.service.MenuAction;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ThermostatExtensionRegistry;
+
+public class MenuRegistryTest {
+
+    @Test
+    public void verifyMenuRegistryReactsToMenuActions() throws InvalidSyntaxException {
+        ArgumentCaptor<ServiceListener> serviceListenerCaptor = ArgumentCaptor.forClass(ServiceListener.class);
+        ArgumentCaptor<String> filterCaptor = ArgumentCaptor.forClass(String.class);
+
+        ActionListener<ThermostatExtensionRegistry.Action> menuListener = mock(ActionListener.class);
+        MenuAction menuAction = mock(MenuAction.class);
+
+        BundleContext context = mock(BundleContext.class);
+        doNothing().when(context).addServiceListener(serviceListenerCaptor.capture(), filterCaptor.capture());
+
+        ServiceReference ref = mock(ServiceReference.class);
+        when(ref.getProperty("objectClass")).thenReturn(MenuAction.class.getName());
+
+        when(context.getService(ref)).thenReturn(menuAction);
+
+        MenuRegistry registry = new MenuRegistry(context);
+        registry.addActionListener(menuListener);
+        registry.start();
+
+        ServiceListener serviceListener = serviceListenerCaptor.getValue();
+        serviceListener.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, ref));
+
+        ArgumentCaptor<ActionEvent> eventCaptor = ArgumentCaptor.forClass(ActionEvent.class);
+        serviceListener.serviceChanged(new ServiceEvent(ServiceEvent.UNREGISTERING, ref));
+
+        verify(menuListener, times(2)).actionPerformed(eventCaptor.capture());
+
+        ActionEvent firstEvent = eventCaptor.getAllValues().get(0);
+        ActionEvent secondEvent = eventCaptor.getAllValues().get(1);
+
+        assertEquals(ThermostatExtensionRegistry.Action.SERVICE_ADDED, firstEvent.getActionId());
+        assertEquals(ThermostatExtensionRegistry.Action.SERVICE_REMOVED, secondEvent.getActionId());
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/SearchFieldSwingViewTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,197 @@
+/*
+ * 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.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 java.awt.FlowLayout;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+
+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.JButtonFixture;
+import org.fest.swing.fixture.JTextComponentFixture;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import com.redhat.thermostat.client.core.views.SearchFieldView;
+import com.redhat.thermostat.client.swing.views.SearchFieldSwingView;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+
+@RunWith(CacioFESTRunner.class)
+public class SearchFieldSwingViewTest {
+
+    private final String OTHER_COMPONENT_NAME = "other";
+
+    private JFrame frame;
+    private SearchFieldSwingView searchField;
+    private JButton otherComponent;
+    private FrameFixture frameFixture;
+
+    @BeforeClass
+    public static void setUpOnce() {
+        FailOnThreadViolationRepaintManager.install();
+    }
+
+    @Before
+    public void setUp() {
+        GuiActionRunner.execute(new GuiTask() {
+
+
+            @Override
+            protected void executeInEDT() throws Throwable {
+                frame = new JFrame();
+                frame.setLayout(new FlowLayout());
+                searchField = new SearchFieldSwingView();
+                frame.add(searchField);
+                otherComponent = new JButton();
+                otherComponent.setName(OTHER_COMPONENT_NAME);
+                frame.add(otherComponent);
+            }
+        });
+        frameFixture = new FrameFixture(frame);
+    }
+
+    @After
+    public void tearDown() {
+        frameFixture.cleanUp();
+        frameFixture = null;
+    }
+
+    @Test
+    public void verifyInitialSearchString() {
+        frameFixture.show();
+
+        assertEquals("", searchField.getSearchText());
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void verifyLabelShownByDefault() {
+        final String LABEL = "search label to help users";
+        searchField.setLabel(LABEL);
+
+        frameFixture.show();
+        JTextComponentFixture textBox = frameFixture.textBox(SearchFieldView.VIEW_NAME);
+        assertEquals(LABEL, textBox.text());
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void verifyLabelHiddenAndShownProperly() {
+        final String LABEL = "search label to help users";
+        final String USER_TEXT = "java";
+        searchField.setLabel(LABEL);
+
+        frameFixture.show();
+        JTextComponentFixture textBox = frameFixture.textBox(SearchFieldView.VIEW_NAME);
+        assertEquals(LABEL, textBox.text());
+
+        textBox.enterText(USER_TEXT);
+
+        textBox.deleteText();
+
+        JButtonFixture button = frameFixture.button(OTHER_COMPONENT_NAME);
+        button.focus();
+
+        assertEquals(LABEL, textBox.text());
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void verifySearchTextTypedIsReturned() {
+        frameFixture.show();
+
+        final String SEARCH_TEXT = "test";
+        JTextComponentFixture textBox = frameFixture.textBox(SearchFieldView.VIEW_NAME);
+        textBox.enterText(SEARCH_TEXT);
+        String actual = searchField.getSearchText();
+        assertEquals(SEARCH_TEXT, actual);
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void verifyTextSetIsShown() {
+        frameFixture.show();
+
+        final String SEARCH_TEXT = "test";
+        searchField.setSearchText(SEARCH_TEXT);
+        JTextComponentFixture textBox = frameFixture.textBox(SearchFieldView.VIEW_NAME);
+        String actual = textBox.text();
+        assertEquals(SEARCH_TEXT, actual);
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void verifyListenersAreFiredOnTextEntry() {
+        frameFixture.show();
+
+        final String SEARCH_TEXT = "test";
+        ActionListener<SearchFieldView.SearchAction> listener = mock(ActionListener.class);
+
+        JTextComponentFixture textBox = frameFixture.textBox(SearchFieldView.VIEW_NAME);
+
+        searchField.addActionListener(listener);
+
+        textBox.enterText(SEARCH_TEXT);
+
+        verify(listener, times(SEARCH_TEXT.length())).actionPerformed(
+                new ActionEvent<SearchFieldView.SearchAction>(searchField, SearchFieldView.SearchAction.TEXT_CHANGED));
+
+        textBox.enterText("\n");
+
+        verify(listener).actionPerformed(
+                new ActionEvent<SearchFieldView.SearchAction>(searchField, SearchFieldView.SearchAction.PERFORM_SEARCH));
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/osgi/ApplicationServiceProviderTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.internal.osgi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ApplicationServiceProviderTest {
+
+    private ApplicationServiceProvider provider;
+
+    @Before
+    public void setUp() {
+        provider = new ApplicationServiceProvider();
+    }
+
+    @After
+    public void tearDown() {
+        provider = null;
+    }
+
+    @Test
+    public void testCache() {
+        provider.getApplicationCache().addAttribute("test", "fluff");
+        assertEquals("fluff", provider.getApplicationCache().getAttribute("test"));
+    }
+
+    @Test
+    public void testApplicationExecutor() throws Exception {
+        assertNotNull(provider.getApplicationExecutor());
+        final String obj = "test";
+        Future<String> future = provider.getApplicationExecutor().submit(new Callable<String>() {
+
+            @Override
+            public String call() throws Exception {
+                return obj;
+            }
+        });
+        String result = future.get();
+        assertSame(result, obj);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/osgi/ThermostatActivatorTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,95 @@
+/*
+ * 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.swing.internal.osgi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.client.core.views.AgentInformationViewProvider;
+import com.redhat.thermostat.client.core.views.ClientConfigViewProvider;
+import com.redhat.thermostat.client.core.views.HostCpuViewProvider;
+import com.redhat.thermostat.client.core.views.HostInformationViewProvider;
+import com.redhat.thermostat.client.core.views.HostMemoryViewProvider;
+import com.redhat.thermostat.client.core.views.HostOverviewViewProvider;
+import com.redhat.thermostat.client.core.views.SummaryViewProvider;
+import com.redhat.thermostat.client.core.views.VmCpuViewProvider;
+import com.redhat.thermostat.client.core.views.VmGcViewProvider;
+import com.redhat.thermostat.client.core.views.VmInformationViewProvider;
+import com.redhat.thermostat.client.core.views.VmOverviewViewProvider;
+import com.redhat.thermostat.client.osgi.service.HostDecorator;
+import com.redhat.thermostat.client.swing.internal.HostIconDecorator;
+import com.redhat.thermostat.client.swing.views.SwingAgentInformationViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingClientConfigurationViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingHostCpuViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingHostInformationViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingHostMemoryViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingHostOverviewViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingSummaryViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingVmCpuViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingVmGcViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingVmInformationViewProvider;
+import com.redhat.thermostat.client.swing.views.SwingVmOverviewViewProvider;
+import com.redhat.thermostat.test.StubBundleContext;
+
+public class ThermostatActivatorTest {
+
+    @Test
+    public void verifyAllExpectedServicesAreRegistered() throws Exception {
+        StubBundleContext ctx = new StubBundleContext();
+
+        ThermostatActivator activator = new ThermostatActivator();
+
+        activator.start(ctx);
+
+        assertTrue(ctx.isServiceRegistered(HostDecorator.class.getName(), HostIconDecorator.class));
+        assertTrue(ctx.isServiceRegistered(SummaryViewProvider.class.getName(), SwingSummaryViewProvider.class));
+        assertTrue(ctx.isServiceRegistered(HostInformationViewProvider.class.getName(), SwingHostInformationViewProvider.class));
+        assertTrue(ctx.isServiceRegistered(HostMemoryViewProvider.class.getName(), SwingHostMemoryViewProvider.class));
+        assertTrue(ctx.isServiceRegistered(HostCpuViewProvider.class.getName(), SwingHostCpuViewProvider.class));
+        assertTrue(ctx.isServiceRegistered(HostOverviewViewProvider.class.getName(), SwingHostOverviewViewProvider.class));
+        assertTrue(ctx.isServiceRegistered(VmInformationViewProvider.class.getName(), SwingVmInformationViewProvider.class));
+        assertTrue(ctx.isServiceRegistered(VmCpuViewProvider.class.getName(), SwingVmCpuViewProvider.class));
+        assertTrue(ctx.isServiceRegistered(VmGcViewProvider.class.getName(), SwingVmGcViewProvider.class));
+        assertTrue(ctx.isServiceRegistered(VmOverviewViewProvider.class.getName(), SwingVmOverviewViewProvider.class));
+        assertTrue(ctx.isServiceRegistered(AgentInformationViewProvider.class.getName(), SwingAgentInformationViewProvider.class));
+        assertTrue(ctx.isServiceRegistered(ClientConfigViewProvider.class.getName(), SwingClientConfigurationViewProvider.class));
+        
+        assertEquals(12, ctx.getAllServices().size());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/views/AgentInformationDisplayFrameTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,264 @@
+/*
+ * 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.swing.views;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.util.HashMap;
+import java.util.Map;
+
+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.edt.GuiTask;
+import org.fest.swing.fixture.FrameFixture;
+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.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import com.redhat.thermostat.client.core.views.AgentInformationDisplayView;
+import com.redhat.thermostat.client.core.views.AgentInformationDisplayView.ConfigurationAction;
+import com.redhat.thermostat.client.swing.views.AgentInformationDisplayFrame;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+
+@RunWith(CacioFESTRunner.class)
+public class AgentInformationDisplayFrameTest {
+
+    private AgentInformationDisplayFrame agentConfigFrame;
+    private FrameFixture fixture;
+    private ActionListener<AgentInformationDisplayView.ConfigurationAction> l;
+
+    @BeforeClass
+    public static void setUpOnce() {
+        FailOnThreadViolationRepaintManager.install();
+    }
+
+    @Before
+    public void setUp() {
+        agentConfigFrame = GuiActionRunner.execute(new GuiQuery<AgentInformationDisplayFrame>() {
+
+            @Override
+            protected AgentInformationDisplayFrame executeInEDT() throws Throwable {
+                return new AgentInformationDisplayFrame();
+            }
+        });
+
+        @SuppressWarnings("unchecked")
+        ActionListener<AgentInformationDisplayView.ConfigurationAction> listener = mock(ActionListener.class);
+        l = listener;
+        agentConfigFrame.addConfigurationListener(l);
+
+        fixture = new FrameFixture(agentConfigFrame.getFrame());
+    }
+
+    @After
+    public void tearDown() {
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                agentConfigFrame.hideDialog();
+            }
+        });
+
+        fixture.requireNotVisible();
+        agentConfigFrame.removeConfigurationListener(l);
+
+        fixture.cleanUp();
+        fixture = null;
+    }
+
+    @Category(GUITest.class)
+    @GUITest
+    @Test
+    public void testWindowClose() {
+        fixture.show();
+
+        fixture.close();
+
+        verify(l).actionPerformed(eq(new ActionEvent<>(agentConfigFrame, AgentInformationDisplayView.ConfigurationAction.CLOSE)));
+    }
+
+    @Category(GUITest.class)
+    @GUITest
+    @Test
+    public void testClickOnCloseButton() {
+        fixture.show();
+
+        fixture.button("close").click();
+
+        fixture.robot.waitForIdle();
+
+        verify(l).actionPerformed(eq(new ActionEvent<>(agentConfigFrame, AgentInformationDisplayView.ConfigurationAction.CLOSE)));
+    }
+
+    @Category(GUITest.class)
+    @GUITest
+    @Test
+    public void testAddingAgentWorks() {
+        fixture.show();
+        JListFixture list = fixture.list("agentList");
+        assertArrayEquals(new String[0], list.contents());
+
+        agentConfigFrame.addAgent("test-agent");
+
+        assertArrayEquals(new String[] { "test-agent" }, list.contents());
+    }
+
+    @Category(GUITest.class)
+    @GUITest
+    @Test
+    public void testSelectingAgentWorks() {
+        fixture.show();
+        agentConfigFrame.addAgent("testAgent");
+        JListFixture list = fixture.list("agentList");
+
+        list.selectItem("testAgent");
+
+        verify(l, atLeast(1)).actionPerformed(eq(new ActionEvent<>(agentConfigFrame, AgentInformationDisplayView.ConfigurationAction.SWITCH_AGENT)));
+    }
+
+    @Category(GUITest.class)
+    @GUITest
+    @Test
+    public void testFirstAddedAgentIsAutomaticallySelected() {
+        fixture.show();
+        agentConfigFrame.addAgent("testAgent");
+
+        fixture.robot.waitForIdle();
+
+        verify(l).actionPerformed(eq(new ActionEvent<>(agentConfigFrame, AgentInformationDisplayView.ConfigurationAction.SWITCH_AGENT)));
+    }
+
+    @Category(GUITest.class)
+    @GUITest
+    @Test
+    public void testRemovingAllAgentsWorks() {
+        fixture.show();
+        agentConfigFrame.addAgent("test-agent");
+        JListFixture list = fixture.list("agentList");
+
+        agentConfigFrame.clearAllAgents();
+
+        assertArrayEquals(new String[0], list.contents());
+    }
+
+    @Category(GUITest.class)
+    @GUITest
+    @Test
+    public void testInitialInformation() {
+        fixture.show();
+
+        String EMPTY_TEXT = "---";
+
+        assertEquals(EMPTY_TEXT, fixture.textBox("agentName").text());
+        assertEquals(EMPTY_TEXT, fixture.textBox("agentId").text());
+        assertEquals(EMPTY_TEXT, fixture.textBox("commandAddress").text());
+        assertEquals(EMPTY_TEXT, fixture.textBox("startTime").text());
+        assertEquals(EMPTY_TEXT, fixture.textBox("stopTime").text());
+        assertEquals(EMPTY_TEXT, fixture.textBox("backendDescription").text());
+
+    }
+
+    @Category(GUITest.class)
+    @GUITest
+    @Test
+    public void testUpdatingAgentInformationWorks() {
+
+        final String AGENT_NAME = "the-agent-name";
+        final String AGENT_ID = "the-agent-id";
+        final String COMMAND_ADDRESS = "agent-command-channel-address";
+        final String START_TIME = "some-start-time";
+        final String STOP_TIME = "a-certain-stop-time";
+
+        agentConfigFrame.setSelectedAgentName(AGENT_NAME);
+        agentConfigFrame.setSelectedAgentId(AGENT_ID);
+        agentConfigFrame.setSelectedAgentCommandAddress(COMMAND_ADDRESS);
+        agentConfigFrame.setSelectedAgentStartTime(START_TIME);
+        agentConfigFrame.setSelectedAgentStopTime(STOP_TIME);
+
+        fixture.show();
+
+        assertEquals(AGENT_NAME, fixture.textBox("agentName").text());
+        assertEquals(AGENT_ID, fixture.textBox("agentId").text());
+        assertEquals(COMMAND_ADDRESS, fixture.textBox("commandAddress").text());
+        assertEquals(START_TIME, fixture.textBox("startTime").text());
+        assertEquals(STOP_TIME, fixture.textBox("stopTime").text());
+    }
+
+    @Category(GUITest.class)
+    @GUITest
+    @Test
+    public void testBackendDescriptionIsQueriedAndDisplayed() {
+        final String BACKEND_NAME = "foo";
+        final String BACKEND_STATUS = "bar";
+        final String BACKEND_DESCRIPTION = "baz";
+
+        Map<String, String> statusMap = new HashMap<>();
+        statusMap.put(BACKEND_NAME, BACKEND_STATUS);
+
+        fixture.show();
+
+        agentConfigFrame.setSelectedAgentBackendStatus(statusMap);
+
+        assertEquals(1, fixture.table("backends").rowCount());
+
+        String[] rowContents = fixture.table("backends").contents()[0];
+        assertArrayEquals(new String[] { BACKEND_NAME, BACKEND_STATUS }, rowContents);
+
+        fixture.table("backends").selectRows(0);
+
+        verify(l).actionPerformed(new ActionEvent<ConfigurationAction>(agentConfigFrame, ConfigurationAction.SHOW_BACKEND_DESCRIPTION));
+
+        agentConfigFrame.setSelectedAgentBackendDescription(BACKEND_DESCRIPTION);
+
+        assertEquals(BACKEND_DESCRIPTION, fixture.textBox("backendDescription").text());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/views/ClientConfigurationSwingTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,195 @@
+/*
+ * 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.swing.views;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import javax.swing.UIManager;
+
+import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
+
+import org.fest.swing.annotation.GUITest;
+import org.fest.swing.core.matcher.JButtonMatcher;
+import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
+import org.fest.swing.edt.GuiActionRunner;
+import org.fest.swing.edt.GuiQuery;
+import org.fest.swing.fixture.DialogFixture;
+import org.fest.swing.fixture.JButtonFixture;
+import org.fest.swing.fixture.JCheckBoxFixture;
+import org.fest.swing.fixture.JTextComponentFixture;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import com.redhat.thermostat.client.core.views.ClientConfigurationView;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.test.Bug;
+
+@RunWith(CacioFESTRunner.class)
+public class ClientConfigurationSwingTest {
+    
+    private ClientConfigurationSwing frame;
+    private DialogFixture frameFixture;
+    private ActionListener<ClientConfigurationView.Action> l;
+
+    @BeforeClass
+    public static void setUpOnce() {
+        FailOnThreadViolationRepaintManager.install();
+    }
+
+    @SuppressWarnings("unchecked") // ActionListener
+    @Before
+    public void setUp() {
+        
+        frame = GuiActionRunner.execute(new GuiQuery<ClientConfigurationSwing>() {
+
+            @Override
+            protected ClientConfigurationSwing executeInEDT() throws Throwable {
+                return new ClientConfigurationSwing();
+            }
+        });
+        l = mock(ActionListener.class);
+        frame.addListener(l);
+        frame.showDialog();
+        assertNotNull(frame.getDialog());
+        frameFixture = new DialogFixture(frame.getDialog());
+
+    }
+
+    @After
+    public void tearDown() {
+        frame.hideDialog();
+
+        frameFixture.cleanUp();
+        frame.removeListener(l);
+        frame = null;
+        l = null;
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void testConnectionUrlText() {
+
+        JTextComponentFixture textBox = frameFixture.textBox("connectionUrl");
+        textBox.enterText("foobar");
+
+        assertEquals("foobar", frame.getConnectionUrl());
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void testPasswordText() {
+
+        JTextComponentFixture textBox = frameFixture.textBox("password");
+        textBox.enterText("foobar");
+
+        assertEquals("foobar", frame.getPassword());
+    }
+    
+    @Category(GUITest.class)
+    @Test
+    public void testUsernameText() {
+
+        JTextComponentFixture textBox = frameFixture.textBox("username");
+        textBox.enterText("foobar");
+
+        assertEquals("foobar", frame.getUserName());
+    }
+    
+    @Category(GUITest.class)
+    @Test
+    public void testSaveEntitlements() {
+
+        JCheckBoxFixture saveBox = frameFixture.checkBox("saveEntitlements");
+        saveBox.requireEnabled();
+        saveBox.requireNotSelected();
+
+        saveBox.click();
+        assertEquals(true, frame.getSaveEntitlements());
+        
+        saveBox.click();
+        assertEquals(false, frame.getSaveEntitlements());
+    }
+    
+    @Category(GUITest.class)
+    @Test
+    public void testOkayButton() {
+        JButtonFixture button = frameFixture.button(JButtonMatcher.withText("OK"));
+        button.click();
+
+        verify(l).actionPerformed(eq(new ActionEvent<>(frame, ClientConfigurationView.Action.CLOSE_ACCEPT)));
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void testCancelButton() {
+        JButtonFixture button = frameFixture.button(JButtonMatcher.withText(UIManager.getString("OptionPane.cancelButtonText")));
+        button.click();
+
+        verify(l).actionPerformed(eq(new ActionEvent<>(frame, ClientConfigurationView.Action.CLOSE_CANCEL)));
+    }
+
+    @Category(GUITest.class)
+    @Test
+    public void testCloseWindow() {
+        frameFixture.close();
+
+        verify(l).actionPerformed(eq(new ActionEvent<>(frame, ClientConfigurationView.Action.CLOSE_CANCEL)));
+    }
+
+    @Bug(id="1030",
+         summary="Buttons in client preferences dialog should have the same size",
+         url="http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=1030")
+    @Category(GUITest.class)
+    @Test
+    public void testButtonsSameSize() {
+        JButtonFixture cancel = frameFixture.button(JButtonMatcher.withText(UIManager.getString("OptionPane.cancelButtonText")));
+        JButtonFixture ok = frameFixture.button(JButtonMatcher.withText("OK"));
+
+        assertEquals(cancel.target.getSize(), ok.target.getSize());
+
+        frameFixture.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/views/HostInformationPanelTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.swing.views;
+
+import java.lang.reflect.InvocationTargetException;
+
+import javax.swing.JFrame;
+import javax.swing.JTabbedPane;
+
+import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
+import org.fest.swing.edt.GuiActionRunner;
+import org.fest.swing.edt.GuiQuery;
+import org.fest.swing.edt.GuiTask;
+import org.fest.swing.fixture.FrameFixture;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.swing.TabbedPaneMatcher;
+import com.redhat.thermostat.client.swing.views.HostInformationPanel;
+
+public class HostInformationPanelTest {
+
+    private HostInformationPanel panel;
+    private JFrame frame;
+    private FrameFixture window;
+
+    @BeforeClass
+    public static void setUpOnce() {
+        FailOnThreadViolationRepaintManager.install();
+    }
+
+    @Before
+    public void setUp() {
+        panel = createHostInfoPanel();
+
+        frame = GuiActionRunner.execute(new GuiQuery<JFrame>() {
+            @Override
+            protected JFrame executeInEDT() throws Throwable {
+                JFrame jFrame = new JFrame();
+                panel.getUiComponent().setName("panel");
+                jFrame.add(panel.getUiComponent());
+                return jFrame;
+            }
+        });
+
+        window = new FrameFixture(frame);
+        window.show();
+    }
+
+    @After
+    public void tearDown() {
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                frame.dispose();
+            }
+        });
+        window.cleanUp();
+    }
+    
+    private HostInformationPanel createHostInfoPanel() {
+        return GuiActionRunner.execute(new GuiQuery<HostInformationPanel>() {
+            @Override
+            protected HostInformationPanel executeInEDT() throws Throwable {
+                return new HostInformationPanel();
+            }
+        });
+    }
+
+    @Test
+    public void testAddTwice() throws InvocationTargetException, InterruptedException {
+        BasicView mock1 = createHostInfoPanel();
+
+        panel.addChildView("foo1", mock1);
+
+        // The panel in test has no views added so the matcher with a tab count > 0 works
+        // in order to select the right panel.
+        window.panel("panel").tabbedPane(new TabbedPaneMatcher(JTabbedPane.class)).requireTabTitles("foo1");
+
+        BasicView mock2 = createHostInfoPanel();
+        panel.addChildView("foo2", mock2);
+
+        window.panel("panel").tabbedPane(new TabbedPaneMatcher(JTabbedPane.class)).requireTabTitles("foo1", "foo2");
+    }
+
+    @Test
+    public void testAddRemove() throws InvocationTargetException, InterruptedException {
+        BasicView test1 = createHostInfoPanel();
+        BasicView test2 = createHostInfoPanel();
+
+        panel.addChildView("test1", test1);
+        panel.addChildView("test2", test2);
+
+        // The panel in test has no views added so the matcher with a tab count > 0 works
+        // in order to select the right panel.
+        window.panel("panel").tabbedPane(new TabbedPaneMatcher(JTabbedPane.class)).requireTabTitles("test1", "test2");
+
+        panel.removeChildView("test1");
+
+        window.panel("panel").tabbedPane(new TabbedPaneMatcher(JTabbedPane.class)).requireTabTitles("test2");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/vmclassstat/core/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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-vmclassstat</artifactId>
+    <groupId>com.redhat.thermostat</groupId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>thermostat-client-vmclassstat-core</artifactId>
+  <packaging>bundle</packaging>
+  <name>Thermostat Client VmClassStat Core plugin</name>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Private-Package></Private-Package>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-SymbolicName>com.redhat.thermostat.client.classstat.core</Bundle-SymbolicName>
+            <Export-Package>
+              com.redhat.thermostat.client.vmclassstat.core,
+              com.redhat.thermostat.client.vmclassstat.core.locale
+            </Export-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.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>
+  </dependencies>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/vmclassstat/core/src/main/java/com/redhat/thermostat/client/vmclassstat/core/LocaleResources.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.vmclassstat.core;
+
+import com.redhat.thermostat.common.locale.Translate;
+
+public enum LocaleResources {
+
+    VM_INFO_TAB_CLASSES,
+    VM_CLASSES_TITLE,
+    VM_CLASSES_CHART_REAL_TIME_LABEL,
+    VM_CLASSES_CHART_LOADED_CLASSES_LABEL,
+
+    ;
+
+    static final String RESOURCE_BUNDLE =
+            "com.redhat.thermostat.client.vmclassstat.strings";
+
+    public static Translate<LocaleResources> createLocalizer() {
+        return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/vmclassstat/core/src/main/java/com/redhat/thermostat/client/vmclassstat/core/VmClassStatController.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,134 @@
+/*
+ * 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.vmclassstat.core;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import com.redhat.thermostat.client.core.controllers.VmInformationServiceController;
+import com.redhat.thermostat.client.core.views.UIComponent;
+import com.redhat.thermostat.client.core.views.BasicView.Action;
+import com.redhat.thermostat.client.vmclassstat.core.locale.LocaleResources;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.NotImplementedException;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.Timer.SchedulingType;
+import com.redhat.thermostat.common.appctx.ApplicationContext;
+import com.redhat.thermostat.common.dao.VmClassStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
+import com.redhat.thermostat.common.model.VmClassStat;
+
+public class VmClassStatController implements VmInformationServiceController {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private class UpdateChartData implements Runnable {
+        @Override
+        public void run() {
+            long timeStamp = lastSeenTimeStamp;
+            List<VmClassStat> latestClassStats = dao.getLatestClassStats(ref, timeStamp);
+            List<DiscreteTimeData<Long>> timeData = new ArrayList<>();
+            for (VmClassStat stat : latestClassStats) {
+                timeData.add(new DiscreteTimeData<Long>(stat.getTimeStamp(), stat.getLoadedClasses()));
+                timeStamp = Math.max(timeStamp, stat.getTimeStamp());
+            }
+            classesView.addClassCount(timeData);
+            lastSeenTimeStamp = timeStamp;
+        }
+    }
+
+    private final VmClassStatView classesView;
+    private final VmRef ref;
+    private final VmClassStatDAO dao;
+    private final Timer timer;
+    private final Translate<LocaleResources> t = LocaleResources.createLocalizer();
+
+    private volatile long lastSeenTimeStamp = Long.MIN_VALUE;
+
+    public VmClassStatController(VmClassStatDAO vmClassStatDao, VmRef ref, VmClassStatViewProvider viewProvider) {
+        this.ref = ref;
+        dao = vmClassStatDao;
+        timer = ApplicationContext.getInstance().getTimerFactory().createTimer();
+
+        timer.setAction(new UpdateChartData());
+        timer.setSchedulingType(SchedulingType.FIXED_RATE);
+        timer.setTimeUnit(TimeUnit.SECONDS);
+        timer.setDelay(5);
+        timer.setInitialDelay(0);
+
+        classesView = viewProvider.createView();
+
+        classesView.addActionListener(new ActionListener<VmClassStatView.Action>() {
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                switch(actionEvent.getActionId()) {
+                    case HIDDEN:
+                        stop();
+                        break;
+                    case VISIBLE:
+                        start();
+                        break;
+                    default:
+                        throw new NotImplementedException("unknown action: " + actionEvent.getActionId());
+                }
+            }
+        });
+    }
+
+    private void start() {
+        timer.start();
+    }
+
+    private void stop() {
+        timer.stop();
+    }
+
+    @Override
+    public String getLocalizedName() {
+        return t.localize(LocaleResources.VM_INFO_TAB_CLASSES);
+    }
+
+    @Override
+    public UIComponent getView() {
+        return (UIComponent) classesView;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/vmclassstat/core/src/main/java/com/redhat/thermostat/client/vmclassstat/core/VmClassStatService.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.vmclassstat.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.dao.VmClassStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+
+public class VmClassStatService implements VmInformationService {
+
+    private VmFilter filter = new AlwaysMatchFilter();
+
+    private VmClassStatDAO vmClassStatDao;
+
+    public VmClassStatService(VmClassStatDAO vmClassStatDao) {
+        this.vmClassStatDao = vmClassStatDao;
+    }
+    
+    @Override
+    public VmInformationServiceController getInformationServiceController(VmRef ref) {
+        VmClassStatViewProvider viewProvider = OSGIUtils.getInstance().getService(VmClassStatViewProvider.class);
+        return new VmClassStatController(vmClassStatDao, ref, viewProvider);
+    }
+
+    @Override
+    public VmFilter getFilter() {
+        return filter;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/vmclassstat/core/src/main/java/com/redhat/thermostat/client/vmclassstat/core/VmClassStatView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,51 @@
+/*
+ * 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.vmclassstat.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.model.DiscreteTimeData;
+
+public abstract class VmClassStatView extends BasicView implements UIComponent {
+
+    public abstract void clearClassCount();
+
+    public abstract void addClassCount(List<DiscreteTimeData<Long>> data);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/vmclassstat/core/src/main/java/com/redhat/thermostat/client/vmclassstat/core/VmClassStatViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.vmclassstat.core;
+
+import com.redhat.thermostat.client.core.views.ViewProvider;
+
+
+public interface VmClassStatViewProvider extends ViewProvider {
+
+    @Override
+    public VmClassStatView createView();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/vmclassstat/core/src/main/java/com/redhat/thermostat/client/vmclassstat/core/locale/LocaleResources.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.vmclassstat.core.locale;
+
+import com.redhat.thermostat.common.locale.Translate;
+
+public enum LocaleResources {
+
+    VM_LOADED_CLASSES,
+    VM_CLASSES_CHART_REAL_TIME_LABEL,
+    VM_CLASSES_CHART_LOADED_CLASSES_LABEL,
+    VM_INFO_TAB_CLASSES,
+    RESOURCE_MISSING;
+    
+    public static final String RESOURCE_BUNDLE =
+            "com.redhat.thermostat.client.vmclassstat.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/client/vmclassstat/core/src/main/resources/com/redhat/thermostat/client/vmclassstat/locale/strings.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,5 @@
+RESOURCE_MISSING = Missing translation!
+VM_LOADED_CLASSES = Loaded Classes
+VM_CLASSES_CHART_REAL_TIME_LABEL = Time
+VM_CLASSES_CHART_LOADED_CLASSES_LABEL = Number of loaded classes
+VM_INFO_TAB_CLASSES = Classes
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/vmclassstat/core/src/main/resources/com/redhat/thermostat/client/vmclassstat/strings.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,4 @@
+VM_INFO_TAB_CLASSES = Classes
+VM_CLASSES_TITLE = Loaded Classes
+VM_CLASSES_CHART_REAL_TIME_LABEL = Time
+VM_CLASSES_CHART_LOADED_CLASSES_LABEL = Number of loaded classes
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/vmclassstat/core/src/test/java/com/redhat/thermostat/client/vmclassstat/core/LocaleResourcesTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,70 @@
+/*
+ * 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.vmclassstat.core;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import org.junit.Test;
+
+public class LocaleResourcesTest {
+
+    @Test
+    public void testLocalizedStringsArePresent() throws IOException {
+
+        String stringsResource = "/" + LocaleResources.RESOURCE_BUNDLE.replace(".", "/") + ".properties";
+
+        Properties props = new Properties();
+        try (InputStream stream = getClass().getResourceAsStream(stringsResource)) {
+            assertNotNull(stream);
+
+            props.load(stream);
+
+            assertEquals(LocaleResources.values().length, props.values().size());
+            for (LocaleResources resource : LocaleResources.values()) {
+                assertTrue("missing property from resource bound file: " + resource,
+                        props.containsKey(resource.name()));
+            }
+
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/vmclassstat/core/src/test/java/com/redhat/thermostat/client/vmclassstat/core/VmClassStatControllerTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,107 @@
+/*
+ * 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.vmclassstat.core;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.TimerFactory;
+import com.redhat.thermostat.common.appctx.ApplicationContext;
+import com.redhat.thermostat.common.dao.VmClassStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.model.VmClassStat;
+
+public class VmClassStatControllerTest {
+
+    @SuppressWarnings({ "unchecked", "rawtypes" }) // any(List.class)
+    @Test
+    public void testChartUpdate() {
+
+        VmClassStat stat1 = new VmClassStat(123, 12345, 1234);
+        List<VmClassStat> stats = new ArrayList<VmClassStat>();
+        stats.add(stat1);
+
+        VmClassStatDAO vmClassStatDAO = mock(VmClassStatDAO.class);
+        when(vmClassStatDAO.getLatestClassStats(any(VmRef.class), anyInt())).thenReturn(stats).thenReturn(new ArrayList<VmClassStat>());
+
+        VmRef ref = mock(VmRef.class);
+
+        Timer timer = mock(Timer.class);
+        ArgumentCaptor<Runnable> timerActionCaptor = ArgumentCaptor.forClass(Runnable.class);
+        doNothing().when(timer).setAction(timerActionCaptor.capture());
+
+        TimerFactory timerFactory = mock(TimerFactory.class);
+        when(timerFactory.createTimer()).thenReturn(timer);
+        ApplicationContext.getInstance().setTimerFactory(timerFactory);
+
+        VmClassStatView view = mock(VmClassStatView.class);
+        ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addActionListener(viewArgumentCaptor.capture());
+        
+        VmClassStatViewProvider viewProvider = mock(VmClassStatViewProvider.class);
+        when(viewProvider.createView()).thenReturn(view);
+
+        @SuppressWarnings("unused")
+        VmClassStatController controller = new VmClassStatController(vmClassStatDAO, ref, viewProvider);
+
+        ActionListener<VmClassStatView.Action> l = viewArgumentCaptor.getValue();
+
+        l.actionPerformed(new ActionEvent<>(view, VmClassStatView.Action.VISIBLE));
+
+        verify(timer).start();
+        timerActionCaptor.getValue().run();
+        verify(view).addClassCount(any(List.class));
+
+        l.actionPerformed(new ActionEvent<>(view, VmClassStatView.Action.HIDDEN));
+
+        verify(timer).stop();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/vmclassstat/core/src/test/java/com/redhat/thermostat/client/vmclassstat/core/locale/TranslateTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.vmclassstat.core.locale;
+
+import java.io.IOException;
+import java.util.Locale;
+import java.util.Properties;
+
+import junit.framework.Assert;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.locale.Translate;
+
+public class TranslateTest {
+
+    private Locale lang;
+
+    @Before
+    public void setUp() {
+        this.lang = Locale.getDefault();
+        Locale.setDefault(Locale.US);
+    }
+
+    @After
+    public void tearDown() {
+        Locale.setDefault(lang);
+    }
+
+    @Test
+    public void verifyTranslationsAreThere() 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());
+        Translate<LocaleResources> t = LocaleResources.createLocalizer();
+        Assert.assertEquals("Missing translation!", t.localize(LocaleResources.RESOURCE_MISSING));
+        Assert.assertEquals("Classes", t.localize(LocaleResources.VM_INFO_TAB_CLASSES));
+    }
+}
--- a/client/vmclassstat/pom.xml	Fri Oct 26 13:13:42 2012 +0200
+++ b/client/vmclassstat/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -1,80 +1,58 @@
 <?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>
-    <groupId>com.redhat.thermostat</groupId>
     <version>0.5.0-SNAPSHOT</version>
   </parent>
+
   <artifactId>thermostat-client-vmclassstat</artifactId>
-  <packaging>bundle</packaging>
+  <packaging>pom</packaging>
+
   <name>Thermostat Client VmClassStat plugin</name>
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <configuration>
-          <instructions>
-            <Private-Package>com.redhat.thermostat.client.vmclassstat</Private-Package>
-            <Bundle-Activator>com.redhat.thermostat.client.vmclassstat.Activator</Bundle-Activator>
-            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
-            <Bundle-SymbolicName>com.redhat.thermostat.client.classstat</Bundle-SymbolicName>
-            <Export-Package>
-              com.redhat.thermostat.client.vmclassstat.locale,
-            </Export-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>org.jfree</groupId>
-      <artifactId>jfreechart</artifactId>
-    </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>
-  </dependencies>
+
+  <modules>
+    <module>core</module>
+    <module>swing</module>
+  </modules>
+
 </project>
--- a/client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/Activator.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.vmclassstat;
-
-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.osgi.service.ApplicationService;
-import com.redhat.thermostat.common.MultipleServiceTracker;
-import com.redhat.thermostat.common.MultipleServiceTracker.Action;
-import com.redhat.thermostat.common.dao.VmClassStatDAO;
-
-public class Activator implements BundleActivator {
-
-    private MultipleServiceTracker classStatTracker;
-    private ServiceRegistration classStatRegistration;
-
-    @Override
-    public void start(final BundleContext context) throws Exception {
-        VmClassStatViewProvider viewProvider = new SwingVmClassStatViewProvider();
-        context.registerService(VmClassStatViewProvider.class.getName(), viewProvider, null);
-
-        Class<?>[] deps = new Class<?>[] {
-            ApplicationService.class,
-            VmClassStatDAO.class,
-        };
-
-        classStatTracker = new MultipleServiceTracker(context, deps, new Action() {
-
-            @Override
-            public void dependenciesAvailable(Map<String, Object> services) {
-                VmClassStatDAO dao = (VmClassStatDAO) services.get(VmClassStatDAO.class.getName());
-                Objects.requireNonNull(dao);
-                VmClassStatService service = new VmClassStatService(dao);
-                classStatRegistration = context.registerService(VmInformationService.class.getName(), service, null);
-            }
-
-            @Override
-            public void dependenciesUnavailable() {
-                classStatRegistration.unregister();
-            }
-
-        });
-        classStatTracker.open();
-    }
-
-    @Override
-    public void stop(BundleContext context) throws Exception {
-        classStatTracker.close();
-    }
-}
--- a/client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/LocaleResources.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +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.vmclassstat;
-
-import com.redhat.thermostat.common.locale.Translate;
-
-public enum LocaleResources {
-
-    VM_INFO_TAB_CLASSES,
-    VM_CLASSES_TITLE,
-    VM_CLASSES_CHART_REAL_TIME_LABEL,
-    VM_CLASSES_CHART_LOADED_CLASSES_LABEL,
-
-    ;
-
-    static final String RESOURCE_BUNDLE =
-            "com.redhat.thermostat.client.vmclassstat.strings";
-
-    public static Translate<LocaleResources> createLocalizer() {
-        return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class);
-    }
-}
--- a/client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/SwingVmClassStatViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.vmclassstat;
-
-
-public class SwingVmClassStatViewProvider implements VmClassStatViewProvider {
-
-    @Override
-    public VmClassStatView createView() {
-        return new VmClassStatPanel();
-    }
-}
--- a/client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/VmClassStatController.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,134 +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.vmclassstat;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import com.redhat.thermostat.client.core.controllers.VmInformationServiceController;
-import com.redhat.thermostat.client.core.views.UIComponent;
-import com.redhat.thermostat.client.core.views.BasicView.Action;
-import com.redhat.thermostat.client.vmclassstat.locale.LocaleResources;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.NotImplementedException;
-import com.redhat.thermostat.common.Timer;
-import com.redhat.thermostat.common.Timer.SchedulingType;
-import com.redhat.thermostat.common.appctx.ApplicationContext;
-import com.redhat.thermostat.common.dao.VmClassStatDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.model.DiscreteTimeData;
-import com.redhat.thermostat.common.model.VmClassStat;
-
-class VmClassStatController implements VmInformationServiceController {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private class UpdateChartData implements Runnable {
-        @Override
-        public void run() {
-            long timeStamp = lastSeenTimeStamp;
-            List<VmClassStat> latestClassStats = dao.getLatestClassStats(ref, timeStamp);
-            List<DiscreteTimeData<Long>> timeData = new ArrayList<>();
-            for (VmClassStat stat : latestClassStats) {
-                timeData.add(new DiscreteTimeData<Long>(stat.getTimeStamp(), stat.getLoadedClasses()));
-                timeStamp = Math.max(timeStamp, stat.getTimeStamp());
-            }
-            classesView.addClassCount(timeData);
-            lastSeenTimeStamp = timeStamp;
-        }
-    }
-
-    private final VmClassStatView classesView;
-    private final VmRef ref;
-    private final VmClassStatDAO dao;
-    private final Timer timer;
-    private final Translate<LocaleResources> t = LocaleResources.createLocalizer();
-
-    private volatile long lastSeenTimeStamp = Long.MIN_VALUE;
-
-    public VmClassStatController(VmClassStatDAO vmClassStatDao, VmRef ref, VmClassStatViewProvider viewProvider) {
-        this.ref = ref;
-        dao = vmClassStatDao;
-        timer = ApplicationContext.getInstance().getTimerFactory().createTimer();
-
-        timer.setAction(new UpdateChartData());
-        timer.setSchedulingType(SchedulingType.FIXED_RATE);
-        timer.setTimeUnit(TimeUnit.SECONDS);
-        timer.setDelay(5);
-        timer.setInitialDelay(0);
-
-        classesView = viewProvider.createView();
-
-        classesView.addActionListener(new ActionListener<VmClassStatView.Action>() {
-            @Override
-            public void actionPerformed(ActionEvent<Action> actionEvent) {
-                switch(actionEvent.getActionId()) {
-                    case HIDDEN:
-                        stop();
-                        break;
-                    case VISIBLE:
-                        start();
-                        break;
-                    default:
-                        throw new NotImplementedException("unknown action: " + actionEvent.getActionId());
-                }
-            }
-        });
-    }
-
-    private void start() {
-        timer.start();
-    }
-
-    private void stop() {
-        timer.stop();
-    }
-
-    @Override
-    public String getLocalizedName() {
-        return t.localize(LocaleResources.VM_INFO_TAB_CLASSES);
-    }
-
-    @Override
-    public UIComponent getView() {
-        return (UIComponent) classesView;
-    }
-
-}
--- a/client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/VmClassStatPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,169 +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.vmclassstat;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.JComponent;
-import javax.swing.SwingUtilities;
-
-import org.jfree.chart.ChartFactory;
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.axis.NumberAxis;
-import org.jfree.chart.axis.NumberTickUnit;
-import org.jfree.chart.axis.TickUnits;
-import org.jfree.data.RangeType;
-import org.jfree.data.time.FixedMillisecond;
-import org.jfree.data.time.RegularTimePeriod;
-import org.jfree.data.time.TimeSeries;
-import org.jfree.data.time.TimeSeriesCollection;
-
-import com.redhat.thermostat.client.ui.ComponentVisibleListener;
-import com.redhat.thermostat.client.ui.Components;
-import com.redhat.thermostat.client.ui.RecentTimeSeriesChartController;
-import com.redhat.thermostat.client.ui.RecentTimeSeriesChartPanel;
-import com.redhat.thermostat.client.ui.SwingComponent;
-import com.redhat.thermostat.client.vmclassstat.locale.LocaleResources;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.ActionNotifier;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.model.DiscreteTimeData;
-import com.redhat.thermostat.swing.HeaderPanel;
-
-public class VmClassStatPanel extends VmClassStatView implements SwingComponent {
-
-    private static final Translate<LocaleResources> t = LocaleResources.createLocalizer();
-
-    private HeaderPanel visiblePanel;
-    
-    private final TimeSeriesCollection dataset = new TimeSeriesCollection();
-
-    private final ActionNotifier<Action> notifier = new ActionNotifier<Action>(this);
-
-    public VmClassStatPanel() {
-        visiblePanel = new HeaderPanel();
-        // any name works
-        dataset.addSeries(new TimeSeries("class-stat"));
-
-        visiblePanel.setHeader(t.localize(LocaleResources.VM_LOADED_CLASSES));
-
-        JFreeChart chart = ChartFactory.createTimeSeriesChart(
-                null,
-                t.localize(LocaleResources.VM_CLASSES_CHART_REAL_TIME_LABEL),
-                t.localize(LocaleResources.VM_CLASSES_CHART_LOADED_CLASSES_LABEL),
-                dataset,
-                false, false, false);
-
-        TickUnits tickUnits = new TickUnits();
-        tickUnits.add(new NumberTickUnit(1));
-        tickUnits.add(new NumberTickUnit(10));
-        tickUnits.add(new NumberTickUnit(100));
-        tickUnits.add(new NumberTickUnit(1000));
-        tickUnits.add(new NumberTickUnit(10000));
-        tickUnits.add(new NumberTickUnit(100000));
-        tickUnits.add(new NumberTickUnit(1000000));
-
-        NumberAxis axis = (NumberAxis) chart.getXYPlot().getRangeAxis();
-        axis.setStandardTickUnits(tickUnits);
-        axis.setRangeType(RangeType.POSITIVE);
-        axis.setAutoRangeMinimumSize(10);
-
-        JComponent chartPanel = new RecentTimeSeriesChartPanel(new RecentTimeSeriesChartController(chart));
-
-        visiblePanel.setContent(chartPanel);
-
-        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
-            @Override
-            public void componentShown(Component component) {
-                notifier.fireAction(Action.VISIBLE);
-            }
-
-            @Override
-            public void componentHidden(Component component) {
-                notifier.fireAction(Action.HIDDEN);
-            }
-        });
-    }
-
-    @Override
-    public void addActionListener(ActionListener<Action> listener) {
-        notifier.addActionListener(listener);
-    }
-
-    @Override
-    public void removeActionListener(ActionListener<Action> listener) {
-        notifier.addActionListener(listener);
-    }
-
-    @Override
-    public void addClassCount(List<DiscreteTimeData<Long>> data) {
-        final List<DiscreteTimeData<Long>> copy = new ArrayList<>(data);
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                TimeSeries series = dataset.getSeries(0);
-                for (DiscreteTimeData<Long> data: copy) {
-                    RegularTimePeriod period = new FixedMillisecond(data.getTimeInMillis());
-                    if (series.getDataItem(period) == null) {
-                        series.add(period, data.getData(), false);
-                    }
-                }
-                series.fireSeriesChanged();
-            }
-        });
-
-    }
-
-    @Override
-    public void clearClassCount() {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                TimeSeries series = dataset.getSeries(0);
-                series.clear();
-            }
-        });
-    }
-
-    @Override
-    public Component getUiComponent() {
-        return visiblePanel;
-    }
-}
--- a/client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/VmClassStatService.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.vmclassstat;
-
-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.dao.VmClassStatDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-
-class VmClassStatService implements VmInformationService {
-
-    private VmFilter filter = new AlwaysMatchFilter();
-
-    private VmClassStatDAO vmClassStatDao;
-
-    public VmClassStatService(VmClassStatDAO vmClassStatDao) {
-        this.vmClassStatDao = vmClassStatDao;
-    }
-    
-    @Override
-    public VmInformationServiceController getInformationServiceController(VmRef ref) {
-        VmClassStatViewProvider viewProvider = OSGIUtils.getInstance().getService(VmClassStatViewProvider.class);
-        return new VmClassStatController(vmClassStatDao, ref, viewProvider);
-    }
-
-    @Override
-    public VmFilter getFilter() {
-        return filter;
-    }
-}
--- a/client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/VmClassStatView.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +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.vmclassstat;
-
-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.model.DiscreteTimeData;
-
-public abstract class VmClassStatView extends BasicView implements UIComponent {
-
-    public abstract void clearClassCount();
-
-    public abstract void addClassCount(List<DiscreteTimeData<Long>> data);
-
-}
--- a/client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/VmClassStatViewProvider.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.vmclassstat;
-
-import com.redhat.thermostat.client.core.views.ViewProvider;
-
-
-public interface VmClassStatViewProvider extends ViewProvider {
-
-    @Override
-    public VmClassStatView createView();
-}
--- a/client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/locale/LocaleResources.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.vmclassstat.locale;
-
-import com.redhat.thermostat.common.locale.Translate;
-
-public enum LocaleResources {
-
-    VM_LOADED_CLASSES,
-    VM_CLASSES_CHART_REAL_TIME_LABEL,
-    VM_CLASSES_CHART_LOADED_CLASSES_LABEL,
-    VM_INFO_TAB_CLASSES,
-    RESOURCE_MISSING;
-    
-    public static final String RESOURCE_BUNDLE =
-            "com.redhat.thermostat.client.vmclassstat.locale.strings";
-    
-    public static Translate<LocaleResources> createLocalizer() {
-        return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class);
-    }
-}
--- a/client/vmclassstat/src/main/resources/com/redhat/thermostat/client/vmclassstat/locale/strings.properties	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-RESOURCE_MISSING = Missing translation!
-VM_LOADED_CLASSES = Loaded Classes
-VM_CLASSES_CHART_REAL_TIME_LABEL = Time
-VM_CLASSES_CHART_LOADED_CLASSES_LABEL = Number of loaded classes
-VM_INFO_TAB_CLASSES = Classes
\ No newline at end of file
--- a/client/vmclassstat/src/main/resources/com/redhat/thermostat/client/vmclassstat/strings.properties	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-VM_INFO_TAB_CLASSES = Classes
-VM_CLASSES_TITLE = Loaded Classes
-VM_CLASSES_CHART_REAL_TIME_LABEL = Time
-VM_CLASSES_CHART_LOADED_CLASSES_LABEL = Number of loaded classes
--- a/client/vmclassstat/src/test/java/com/redhat/thermostat/client/vmclassstat/ActivatorTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.vmclassstat;
-
-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.client.osgi.service.ApplicationService;
-import com.redhat.thermostat.common.dao.VmClassStatDAO;
-import com.redhat.thermostat.test.StubBundleContext;
-
-public class ActivatorTest {
-
-    @Test
-    public void verifyActivatorDoesNotRegisterServiceOnMissingDeps() throws Exception {
-        StubBundleContext context = new StubBundleContext();
-
-        Activator activator = new Activator();
-
-        activator.start(context);
-
-        // View provider registers unconditionally
-        assertEquals(1, 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();
-        ApplicationService appService = mock(ApplicationService.class);
-        VmClassStatDAO daoService = mock(VmClassStatDAO.class);
-
-        context.registerService(ApplicationService.class, appService, null);
-        context.registerService(VmClassStatDAO.class, daoService, null);
-
-        Activator activator = new Activator();
-
-        activator.start(context);
-
-        assertTrue(context.isServiceRegistered(VmInformationService.class.getName(), VmClassStatService.class));
-
-        activator.stop(context);
-
-        assertEquals(0, context.getServiceListeners().size());
-        assertEquals(3, context.getAllServices().size());
-    }
-
-    @Test
-    public void verifyStartRegistersViewProvider() throws Exception {
-        StubBundleContext ctx = new StubBundleContext();
-        Activator activator = new Activator();
-        activator.start(ctx);
-        assertTrue(ctx.isServiceRegistered(VmClassStatViewProvider.class.getName(), SwingVmClassStatViewProvider.class));
-        assertEquals(1, ctx.getAllServices().size());
-    }
-}
--- a/client/vmclassstat/src/test/java/com/redhat/thermostat/client/vmclassstat/LocaleResourcesTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /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.client.vmclassstat;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-
-import org.junit.Test;
-
-public class LocaleResourcesTest {
-
-    @Test
-    public void testLocalizedStringsArePresent() throws IOException {
-
-        String stringsResource = "/" + LocaleResources.RESOURCE_BUNDLE.replace(".", "/") + ".properties";
-
-        Properties props = new Properties();
-        try (InputStream stream = getClass().getResourceAsStream(stringsResource)) {
-            assertNotNull(stream);
-
-            props.load(stream);
-
-            assertEquals(LocaleResources.values().length, props.values().size());
-            for (LocaleResources resource : LocaleResources.values()) {
-                assertTrue("missing property from resource bound file: " + resource,
-                        props.containsKey(resource.name()));
-            }
-
-        }
-    }
-}
--- a/client/vmclassstat/src/test/java/com/redhat/thermostat/client/vmclassstat/VmClassStatControllerTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +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.vmclassstat;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.Timer;
-import com.redhat.thermostat.common.TimerFactory;
-import com.redhat.thermostat.common.appctx.ApplicationContext;
-import com.redhat.thermostat.common.dao.VmClassStatDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.model.VmClassStat;
-
-public class VmClassStatControllerTest {
-
-    @SuppressWarnings({ "unchecked", "rawtypes" }) // any(List.class)
-    @Test
-    public void testChartUpdate() {
-
-        VmClassStat stat1 = new VmClassStat(123, 12345, 1234);
-        List<VmClassStat> stats = new ArrayList<VmClassStat>();
-        stats.add(stat1);
-
-        VmClassStatDAO vmClassStatDAO = mock(VmClassStatDAO.class);
-        when(vmClassStatDAO.getLatestClassStats(any(VmRef.class), anyInt())).thenReturn(stats).thenReturn(new ArrayList<VmClassStat>());
-
-        VmRef ref = mock(VmRef.class);
-
-        Timer timer = mock(Timer.class);
-        ArgumentCaptor<Runnable> timerActionCaptor = ArgumentCaptor.forClass(Runnable.class);
-        doNothing().when(timer).setAction(timerActionCaptor.capture());
-
-        TimerFactory timerFactory = mock(TimerFactory.class);
-        when(timerFactory.createTimer()).thenReturn(timer);
-        ApplicationContext.getInstance().setTimerFactory(timerFactory);
-
-        VmClassStatView view = mock(VmClassStatView.class);
-        ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class);
-        doNothing().when(view).addActionListener(viewArgumentCaptor.capture());
-        
-        VmClassStatViewProvider viewProvider = mock(VmClassStatViewProvider.class);
-        when(viewProvider.createView()).thenReturn(view);
-
-        @SuppressWarnings("unused")
-        VmClassStatController controller = new VmClassStatController(vmClassStatDAO, ref, viewProvider);
-
-        ActionListener<VmClassStatView.Action> l = viewArgumentCaptor.getValue();
-
-        l.actionPerformed(new ActionEvent<>(view, VmClassStatView.Action.VISIBLE));
-
-        verify(timer).start();
-        timerActionCaptor.getValue().run();
-        verify(view).addClassCount(any(List.class));
-
-        l.actionPerformed(new ActionEvent<>(view, VmClassStatView.Action.HIDDEN));
-
-        verify(timer).stop();
-    }
-
-}
--- a/client/vmclassstat/src/test/java/com/redhat/thermostat/client/vmclassstat/VmClassStatPanelTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +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.vmclassstat;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.JPanel;
-
-import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
-
-import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
-import org.fest.swing.edt.GuiActionRunner;
-import org.fest.swing.edt.GuiTask;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import com.redhat.thermostat.common.model.DiscreteTimeData;
-
-@RunWith(CacioFESTRunner.class)
-public class VmClassStatPanelTest {
-
-    @BeforeClass
-    public static void setUpOnce() {
-        FailOnThreadViolationRepaintManager.install();
-    }
-
-    @Test
-    public void testAddDataTwice() {
-        GuiActionRunner.execute(new GuiTask() {
-            @Override
-            protected void executeInEDT() throws Throwable {
-                VmClassStatPanel panel = new VmClassStatPanel();
-                List<DiscreteTimeData<Long>> data = new ArrayList<>();
-                panel.addClassCount(data);
-                int numComponents = ((JPanel)panel.getUiComponent()).getComponentCount();
-                assertTrue(numComponents > 0);
-                panel.addClassCount(data);
-                assertEquals(numComponents, ((JPanel)panel.getUiComponent()).getComponentCount());
-            }
-        });
-    }
-
-}
--- a/client/vmclassstat/src/test/java/com/redhat/thermostat/client/vmclassstat/locale/TranslateTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +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.vmclassstat.locale;
-
-import java.io.IOException;
-import java.util.Locale;
-import java.util.Properties;
-
-import junit.framework.Assert;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.common.locale.Translate;
-
-public class TranslateTest {
-
-    private Locale lang;
-
-    @Before
-    public void setUp() {
-        this.lang = Locale.getDefault();
-        Locale.setDefault(Locale.US);
-    }
-
-    @After
-    public void tearDown() {
-        Locale.setDefault(lang);
-    }
-
-    @Test
-    public void verifyTranslationsAreThere() 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());
-        Translate<LocaleResources> t = LocaleResources.createLocalizer();
-        Assert.assertEquals("Missing translation!", t.localize(LocaleResources.RESOURCE_MISSING));
-        Assert.assertEquals("Classes", t.localize(LocaleResources.VM_INFO_TAB_CLASSES));
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/vmclassstat/swing/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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-vmclassstat</artifactId>
+    <groupId>com.redhat.thermostat</groupId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>thermostat-client-vmclassstat-swing</artifactId>
+  <packaging>bundle</packaging>
+  <name>Thermostat Client VmClassStat Swing plugin</name>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Private-Package>com.redhat.thermostat.client.vmclassstat.swing</Private-Package>
+            <Bundle-Activator>com.redhat.thermostat.client.vmclassstat.swing.Activator</Bundle-Activator>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-SymbolicName>com.redhat.thermostat.client.classstat.swing</Bundle-SymbolicName>
+            <!-- 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>org.jfree</groupId>
+      <artifactId>jfreechart</artifactId>
+    </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-client-vmclassstat-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/vmclassstat/swing/src/main/java/com/redhat/thermostat/client/vmclassstat/swing/Activator.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.vmclassstat.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.osgi.service.ApplicationService;
+import com.redhat.thermostat.client.vmclassstat.core.VmClassStatService;
+import com.redhat.thermostat.client.vmclassstat.core.VmClassStatViewProvider;
+import com.redhat.thermostat.common.MultipleServiceTracker;
+import com.redhat.thermostat.common.MultipleServiceTracker.Action;
+import com.redhat.thermostat.common.dao.VmClassStatDAO;
+
+public class Activator implements BundleActivator {
+
+    private MultipleServiceTracker classStatTracker;
+    private ServiceRegistration classStatRegistration;
+
+    @Override
+    public void start(final BundleContext context) throws Exception {
+        VmClassStatViewProvider viewProvider = new SwingVmClassStatViewProvider();
+        context.registerService(VmClassStatViewProvider.class.getName(), viewProvider, null);
+
+        Class<?>[] deps = new Class<?>[] {
+            ApplicationService.class,
+            VmClassStatDAO.class,
+        };
+
+        classStatTracker = new MultipleServiceTracker(context, deps, new Action() {
+
+            @Override
+            public void dependenciesAvailable(Map<String, Object> services) {
+                VmClassStatDAO dao = (VmClassStatDAO) services.get(VmClassStatDAO.class.getName());
+                Objects.requireNonNull(dao);
+                VmClassStatService service = new VmClassStatService(dao);
+                classStatRegistration = context.registerService(VmInformationService.class.getName(), service, null);
+            }
+
+            @Override
+            public void dependenciesUnavailable() {
+                classStatRegistration.unregister();
+            }
+
+        });
+        classStatTracker.open();
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        classStatTracker.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/vmclassstat/swing/src/main/java/com/redhat/thermostat/client/vmclassstat/swing/SwingVmClassStatViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.vmclassstat.swing;
+
+import com.redhat.thermostat.client.vmclassstat.core.VmClassStatView;
+import com.redhat.thermostat.client.vmclassstat.core.VmClassStatViewProvider;
+
+
+public class SwingVmClassStatViewProvider implements VmClassStatViewProvider {
+
+    @Override
+    public VmClassStatView createView() {
+        return new VmClassStatPanel();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/vmclassstat/swing/src/main/java/com/redhat/thermostat/client/vmclassstat/swing/VmClassStatPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,168 @@
+/*
+ * 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.vmclassstat.swing;
+
+import java.awt.Component;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.JComponent;
+import javax.swing.SwingUtilities;
+
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.axis.NumberTickUnit;
+import org.jfree.chart.axis.TickUnits;
+import org.jfree.data.RangeType;
+import org.jfree.data.time.FixedMillisecond;
+import org.jfree.data.time.RegularTimePeriod;
+import org.jfree.data.time.TimeSeries;
+import org.jfree.data.time.TimeSeriesCollection;
+
+import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.client.swing.components.HeaderPanel;
+import com.redhat.thermostat.client.swing.components.RecentTimeSeriesChartPanel;
+import com.redhat.thermostat.client.ui.ComponentVisibleListener;
+import com.redhat.thermostat.client.ui.RecentTimeSeriesChartController;
+import com.redhat.thermostat.client.vmclassstat.core.VmClassStatView;
+import com.redhat.thermostat.client.vmclassstat.core.locale.LocaleResources;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ActionNotifier;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
+
+public class VmClassStatPanel extends VmClassStatView implements SwingComponent {
+
+    private static final Translate<LocaleResources> t = LocaleResources.createLocalizer();
+
+    private HeaderPanel visiblePanel;
+    
+    private final TimeSeriesCollection dataset = new TimeSeriesCollection();
+
+    private final ActionNotifier<Action> notifier = new ActionNotifier<Action>(this);
+
+    public VmClassStatPanel() {
+        visiblePanel = new HeaderPanel();
+        // any name works
+        dataset.addSeries(new TimeSeries("class-stat"));
+
+        visiblePanel.setHeader(t.localize(LocaleResources.VM_LOADED_CLASSES));
+
+        JFreeChart chart = ChartFactory.createTimeSeriesChart(
+                null,
+                t.localize(LocaleResources.VM_CLASSES_CHART_REAL_TIME_LABEL),
+                t.localize(LocaleResources.VM_CLASSES_CHART_LOADED_CLASSES_LABEL),
+                dataset,
+                false, false, false);
+
+        TickUnits tickUnits = new TickUnits();
+        tickUnits.add(new NumberTickUnit(1));
+        tickUnits.add(new NumberTickUnit(10));
+        tickUnits.add(new NumberTickUnit(100));
+        tickUnits.add(new NumberTickUnit(1000));
+        tickUnits.add(new NumberTickUnit(10000));
+        tickUnits.add(new NumberTickUnit(100000));
+        tickUnits.add(new NumberTickUnit(1000000));
+
+        NumberAxis axis = (NumberAxis) chart.getXYPlot().getRangeAxis();
+        axis.setStandardTickUnits(tickUnits);
+        axis.setRangeType(RangeType.POSITIVE);
+        axis.setAutoRangeMinimumSize(10);
+
+        JComponent chartPanel = new RecentTimeSeriesChartPanel(new RecentTimeSeriesChartController(chart));
+
+        visiblePanel.setContent(chartPanel);
+
+        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+
+            @Override
+            public void componentHidden(Component component) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
+    }
+
+    @Override
+    public void addActionListener(ActionListener<Action> listener) {
+        notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void removeActionListener(ActionListener<Action> listener) {
+        notifier.addActionListener(listener);
+    }
+
+    @Override
+    public void addClassCount(List<DiscreteTimeData<Long>> data) {
+        final List<DiscreteTimeData<Long>> copy = new ArrayList<>(data);
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                TimeSeries series = dataset.getSeries(0);
+                for (DiscreteTimeData<Long> data: copy) {
+                    RegularTimePeriod period = new FixedMillisecond(data.getTimeInMillis());
+                    if (series.getDataItem(period) == null) {
+                        series.add(period, data.getData(), false);
+                    }
+                }
+                series.fireSeriesChanged();
+            }
+        });
+
+    }
+
+    @Override
+    public void clearClassCount() {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                TimeSeries series = dataset.getSeries(0);
+                series.clear();
+            }
+        });
+    }
+
+    @Override
+    public Component getUiComponent() {
+        return visiblePanel;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/vmclassstat/swing/src/test/java/com/redhat/thermostat/client/vmclassstat/swing/ActivatorTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.client.vmclassstat.swing;
+
+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.client.osgi.service.ApplicationService;
+import com.redhat.thermostat.client.vmclassstat.core.VmClassStatService;
+import com.redhat.thermostat.client.vmclassstat.core.VmClassStatViewProvider;
+import com.redhat.thermostat.common.dao.VmClassStatDAO;
+import com.redhat.thermostat.test.StubBundleContext;
+
+public class ActivatorTest {
+
+    @Test
+    public void verifyActivatorDoesNotRegisterServiceOnMissingDeps() throws Exception {
+        StubBundleContext context = new StubBundleContext();
+
+        Activator activator = new Activator();
+
+        activator.start(context);
+
+        // View provider registers unconditionally
+        assertEquals(1, 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();
+        ApplicationService appService = mock(ApplicationService.class);
+        VmClassStatDAO daoService = mock(VmClassStatDAO.class);
+
+        context.registerService(ApplicationService.class, appService, null);
+        context.registerService(VmClassStatDAO.class, daoService, null);
+
+        Activator activator = new Activator();
+
+        activator.start(context);
+
+        assertTrue(context.isServiceRegistered(VmInformationService.class.getName(), VmClassStatService.class));
+
+        activator.stop(context);
+
+        assertEquals(0, context.getServiceListeners().size());
+        assertEquals(3, context.getAllServices().size());
+    }
+
+    @Test
+    public void verifyStartRegistersViewProvider() throws Exception {
+        StubBundleContext ctx = new StubBundleContext();
+        Activator activator = new Activator();
+        activator.start(ctx);
+        assertTrue(ctx.isServiceRegistered(VmClassStatViewProvider.class.getName(), SwingVmClassStatViewProvider.class));
+        assertEquals(1, ctx.getAllServices().size());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/vmclassstat/swing/src/test/java/com/redhat/thermostat/client/vmclassstat/swing/VmClassStatPanelTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,82 @@
+/*
+ * 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.vmclassstat.swing;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.JPanel;
+
+import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
+
+import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
+import org.fest.swing.edt.GuiActionRunner;
+import org.fest.swing.edt.GuiTask;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.redhat.thermostat.common.model.DiscreteTimeData;
+
+@RunWith(CacioFESTRunner.class)
+public class VmClassStatPanelTest {
+
+    @BeforeClass
+    public static void setUpOnce() {
+        FailOnThreadViolationRepaintManager.install();
+    }
+
+    @Test
+    public void testAddDataTwice() {
+        GuiActionRunner.execute(new GuiTask() {
+            @Override
+            protected void executeInEDT() throws Throwable {
+                VmClassStatPanel panel = new VmClassStatPanel();
+                List<DiscreteTimeData<Long>> data = new ArrayList<>();
+                panel.addClassCount(data);
+                int numComponents = ((JPanel)panel.getUiComponent()).getComponentCount();
+                assertTrue(numComponents > 0);
+                panel.addClassCount(data);
+                assertEquals(numComponents, ((JPanel)panel.getUiComponent()).getComponentCount());
+            }
+        });
+    }
+
+}
--- a/common/core/p2.inf	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-# Instructs Eclipse update manager to auto-start this bundle
-instructions.configure = \
-org.eclipse.equinox.p2.touchpoint.eclipse.setStartLevel(startLevel: 4); \
-org.eclipse.equinox.p2.touchpoint.eclipse.markStarted(started: true);
-instructions.unconfigure = \
-org.eclipse.equinox.p2.touchpoint.eclipse.setStartLevel(startLevel: -1); \
-org.eclipse.equinox.p2.touchpoint.eclipse.markStarted(started: false);
--- a/common/core/pom.xml	Fri Oct 26 13:13:42 2012 +0200
+++ b/common/core/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -97,7 +97,6 @@
             </Private-Package>
             <!-- Do not autogenerate uses clauses in Manifests -->
             <_nouses>true</_nouses>
-            <Include-Resource>META-INF/p2.inf=p2.inf</Include-Resource>
           </instructions>
         </configuration>
       </plugin>
@@ -141,6 +140,14 @@
       <artifactId>commons-beanutils</artifactId>
     </dependency>
     <dependency>
+      <groupId>commons-collections</groupId>
+      <artifactId>commons-collections</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>com.springsource.org.apache.commons.logging</artifactId>
+    </dependency>
+    <dependency>
       <groupId>commons-cli</groupId>
       <artifactId>commons-cli</artifactId>
     </dependency>
@@ -157,8 +164,8 @@
     </dependency>
     
     <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-core</artifactId>
+      <groupId>org.apache.servicemix.bundles</groupId>
+      <artifactId>org.apache.servicemix.bundles.lucene</artifactId>
     </dependency>
     <dependency>
       <groupId>com.sun</groupId>
--- a/common/core/src/main/java/com/redhat/thermostat/common/cli/CommandInfo.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/cli/CommandInfo.java	Fri Oct 26 15:32:56 2012 +0200
@@ -1,3 +1,39 @@
+/*
+ * 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.cli;
 
 import java.util.List;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/cli/CommandInfoNotFoundException.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,52 @@
+/*
+ * 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.cli;
+
+public class CommandInfoNotFoundException extends RuntimeException {
+
+    private String commandName = null;
+
+    public CommandInfoNotFoundException(String commandName) {
+        super("data for command '" + commandName + "' not found");
+
+        this.commandName = commandName;
+    }
+
+    public String getCommandName() {
+        return commandName;
+    }
+}
--- a/common/core/src/main/java/com/redhat/thermostat/common/cli/CommandInfoSource.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/cli/CommandInfoSource.java	Fri Oct 26 15:32:56 2012 +0200
@@ -41,7 +41,7 @@
 
 public interface CommandInfoSource {
 
-    public CommandInfo getCommandInfo(String name);
+    public CommandInfo getCommandInfo(String name) throws CommandInfoNotFoundException;
 
     public Collection<CommandInfo> getCommandInfos();
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/config/ClientPreferences.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/config/ClientPreferences.java	Fri Oct 26 15:32:56 2012 +0200
@@ -41,7 +41,6 @@
 
 import com.redhat.thermostat.utils.keyring.Credentials;
 import com.redhat.thermostat.utils.keyring.Keyring;
-import com.redhat.thermostat.utils.keyring.KeyringProvider;
 
 public class ClientPreferences {
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/locale/Translate.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/locale/Translate.java	Fri Oct 26 15:32:56 2012 +0200
@@ -37,6 +37,7 @@
 package com.redhat.thermostat.common.locale;
 
 import java.text.MessageFormat;
+import java.util.Locale;
 import java.util.ResourceBundle;
 
 public class Translate<T extends Enum<T>> {
@@ -44,7 +45,7 @@
     private final ResourceBundle resourceBundle;
 
     public Translate(String stringResources, Class<T> enumClass) {
-        this(ResourceBundle.getBundle(stringResources), enumClass);
+        this(ResourceBundle.getBundle(stringResources, Locale.getDefault(), enumClass.getClassLoader()), enumClass);
     }
 
     Translate(ResourceBundle resourceBundle, Class<T> enumClass) {
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java	Fri Oct 26 15:32:56 2012 +0200
@@ -140,7 +140,7 @@
                     query.put(name, toInsert.get(name));
                 }
             }
-            coll.update(query, toInsert);
+            coll.update(query, toInsert, true, false);
         } else {
             coll.insert(toInsert);
         }
--- a/common/core/src/main/java/com/redhat/thermostat/test/StubBundleContext.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/test/StubBundleContext.java	Fri Oct 26 15:32:56 2012 +0200
@@ -83,6 +83,7 @@
         }
     }
 
+    private List<Bundle> bundles = new ArrayList<>();
     private List<ServiceInformation> registeredServices = new ArrayList<>();
     private List<ListenerSpec> registeredListeners = new ArrayList<>();
 
@@ -112,7 +113,10 @@
 
     @Override
     public Bundle getBundle(long id) {
-        throw new NotImplementedException();
+        if (id > Integer.MAX_VALUE) {
+            throw new NotImplementedException();
+        }
+        return bundles.get((int) id);
     }
 
     @Override
@@ -204,7 +208,12 @@
 
     @Override
     public ServiceReference getServiceReference(Class clazz) {
-        throw new NotImplementedException();
+        for (ServiceInformation info : registeredServices) {
+            if (info.serviceInterface.equals(clazz)) {
+                return new StubServiceReference(info);
+            }
+        }
+        return null;
     }
 
     @Override
@@ -250,6 +259,10 @@
      * Our custom methods
      */
 
+    public void setBundle(int i, Bundle bundle) {
+        bundles.add(i, bundle);
+    }
+
     public boolean isServiceRegistered(String serviceName, Class<?> implementationClass) {
         for (ServiceInformation info : registeredServices) {
             if (info.serviceInterface.equals(serviceName) && info.implementation.getClass().equals(implementationClass)) {
@@ -279,4 +292,6 @@
         StubServiceRegistration reg = (StubServiceRegistration) registration;
         return reg.getInfo().exportedReferences;
     }
+
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/resources/META-INF/p2.inf	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,7 @@
+# Instructs Eclipse update manager to auto-start this bundle
+instructions.configure = \
+org.eclipse.equinox.p2.touchpoint.eclipse.setStartLevel(startLevel: 4); \
+org.eclipse.equinox.p2.touchpoint.eclipse.markStarted(started: true);
+instructions.unconfigure = \
+org.eclipse.equinox.p2.touchpoint.eclipse.setStartLevel(startLevel: -1); \
+org.eclipse.equinox.p2.touchpoint.eclipse.markStarted(started: false);
--- a/common/core/src/test/java/com/redhat/thermostat/common/storage/MongoStorageTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/storage/MongoStorageTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -497,7 +497,7 @@
 
         ArgumentCaptor<DBObject> queryCaptor = ArgumentCaptor.forClass(DBObject.class);
         ArgumentCaptor<DBObject> valueCaptor = ArgumentCaptor.forClass(DBObject.class);
-        verify(testCollection).update(queryCaptor.capture(), valueCaptor.capture());
+        verify(testCollection).update(queryCaptor.capture(), valueCaptor.capture(), true, false);
 
         DBObject query = queryCaptor.getValue();
         assertEquals(2, query.keySet().size());
--- a/distribution/config/commands/agent.properties	Fri Oct 26 13:13:42 2012 +0200
+++ b/distribution/config/commands/agent.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -8,7 +8,8 @@
           thermostat-killvm-agent-@project.version@.jar, \
           thermostat-thread-collector-@project.version@.jar, \
           thermostat-thread-harvester-@project.version@.jar, \
-          thermostat-system-backend-@project.version@.jar
+          thermostat-system-backend-@project.version@.jar, \
+          netty.jar
 
 description = starts and stops the thermostat agent
 
--- a/distribution/config/commands/dump-heap.properties	Fri Oct 26 13:13:42 2012 +0200
+++ b/distribution/config/commands/dump-heap.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -2,9 +2,9 @@
           thermostat-client-core-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
           thermostat-client-command-@project.version@.jar, \
-          thermostat-client-heapdumper-@project.version@.jar, \
-          thermostat-swing-components-@project.version@.jar, \
-          thermostat-laf-@project.version@.jar
+          thermostat-client-heapdumper-core-@project.version@.jar, \
+          thermostat-laf-@project.version@.jar, \
+          netty.jar
 
 description = trigger a heap dump on the VM
 
--- a/distribution/config/commands/find-objects.properties	Fri Oct 26 13:13:42 2012 +0200
+++ b/distribution/config/commands/find-objects.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -2,9 +2,9 @@
           thermostat-client-core-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
           thermostat-client-command-@project.version@.jar, \
-          thermostat-client-heapdumper-@project.version@.jar, \
-          thermostat-swing-components-@project.version@.jar, \
-          thermostat-laf-@project.version@.jar
+          thermostat-client-heapdumper-core-@project.version@.jar, \
+          thermostat-laf-@project.version@.jar, \
+          netty.jar
 
 description = Finds objects in a heapdump
 
--- a/distribution/config/commands/find-root.properties	Fri Oct 26 13:13:42 2012 +0200
+++ b/distribution/config/commands/find-root.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -2,9 +2,9 @@
           thermostat-client-core-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
           thermostat-client-command-@project.version@.jar, \
-          thermostat-client-heapdumper-@project.version@.jar, \
-          thermostat-swing-components-@project.version@.jar, \
-          thermostat-laf-@project.version@.jar
+          thermostat-client-heapdumper-core-@project.version@.jar, \
+          thermostat-laf-@project.version@.jar, \
+          netty.jar
 
 description = finds the shortest path from an object to a GC root
 
--- a/distribution/config/commands/gui.properties	Fri Oct 26 13:13:42 2012 +0200
+++ b/distribution/config/commands/gui.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -4,13 +4,17 @@
           thermostat-web-client-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
           thermostat-client-core-@project.version@.jar, \
+          thermostat-client-swing-@project.version@.jar, \
           thermostat-client-command-@project.version@.jar, \
-          thermostat-client-heapdumper-@project.version@.jar, \
+          thermostat-client-heapdumper-core-@project.version@.jar, \
+          thermostat-client-heapdumper-swing-@project.version@.jar, \
           thermostat-killvm-client-swing-@project.version@.jar, \
-          thermostat-client-vmclassstat-@project.version@.jar, \
-          thermostat-osgi-living-vm-filter-@project.version@.jar, \
-          thermostat-osgi-memory-stats-panel-@project.version@.jar, \
-          thermostat-swing-components-@project.version@.jar, \
+          thermostat-client-vmclassstat-core-@project.version@.jar, \
+          thermostat-client-vmclassstat-swing-@project.version@.jar, \
+          thermostat-osgi-living-vm-filter-core-@project.version@.jar, \
+          thermostat-osgi-living-vm-filter-swing-@project.version@.jar, \
+          thermostat-osgi-memory-stats-panel-core-@project.version@.jar, \
+          thermostat-osgi-memory-stats-panel-swing-@project.version@.jar, \
           thermostat-laf-@project.version@.jar, \
           thermostat-thread-collector-@project.version@.jar, \
           thermostat-thread-client-swing-@project.version@.jar, \
@@ -18,8 +22,8 @@
           thermostat-thread-client-common-@project.version@.jar, \
           thermostat-osgi-process-handler-@project.version@.jar, \
           httpcore-osgi-@httpcomponents.version@.jar, \
-          httpclient-osgi-@httpcomponents.version@.jar
-          
+          httpclient-osgi-@httpcomponents.version@.jar, \
+          netty.jar
 
 description = launches the GUI client
 
--- a/distribution/config/commands/list-heap-dumps.properties	Fri Oct 26 13:13:42 2012 +0200
+++ b/distribution/config/commands/list-heap-dumps.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -2,9 +2,9 @@
           thermostat-client-core-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
           thermostat-client-command-@project.version@.jar, \
-          thermostat-client-heapdumper-@project.version@.jar, \
-          thermostat-swing-components-@project.version@.jar, \
-          thermostat-laf-@project.version@.jar
+          thermostat-client-heapdumper-core-@project.version@.jar, \
+          thermostat-laf-@project.version@.jar, \
+          netty.jar
 
 description = list all heap dumps
 
--- a/distribution/config/commands/object-info.properties	Fri Oct 26 13:13:42 2012 +0200
+++ b/distribution/config/commands/object-info.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -2,9 +2,9 @@
           thermostat-client-core-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
           thermostat-client-command-@project.version@.jar, \
-          thermostat-client-heapdumper-@project.version@.jar, \
-          thermostat-swing-components-@project.version@.jar, \
-          thermostat-laf-@project.version@.jar
+          thermostat-client-heapdumper-core-@project.version@.jar, \
+          thermostat-laf-@project.version@.jar, \
+          netty.jar
 
 description = prints information about an object in a heap dump
 
--- a/distribution/config/commands/ping.properties	Fri Oct 26 13:13:42 2012 +0200
+++ b/distribution/config/commands/ping.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -1,5 +1,6 @@
 bundles = thermostat-common-command-@project.version@.jar, \
-          thermostat-client-command-@project.version@.jar
+          thermostat-client-command-@project.version@.jar, \
+          netty.jar
 
 description = using the Command Channel, send a ping to a running agent
 
--- a/distribution/config/commands/save-heap-dump-to-file.properties	Fri Oct 26 13:13:42 2012 +0200
+++ b/distribution/config/commands/save-heap-dump-to-file.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -2,9 +2,9 @@
           thermostat-client-core-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
           thermostat-client-command-@project.version@.jar, \
-          thermostat-client-heapdumper-@project.version@.jar, \
-          thermostat-swing-components-@project.version@.jar, \
-          thermostat-laf-@project.version@.jar
+          thermostat-client-heapdumper-core-@project.version@.jar, \
+          thermostat-laf-@project.version@.jar, \
+          netty.jar
 
 description = saves a heap dump to a local file
 
--- a/distribution/config/commands/service.properties	Fri Oct 26 13:13:42 2012 +0200
+++ b/distribution/config/commands/service.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -1,5 +1,4 @@
 bundles = thermostat-agent-core-@project.version@.jar, \
-          gson-2.2.2.jar, \
           thermostat-web-common-@project.version@.jar, \
           thermostat-web-server-@project.version@.jar, \
           thermostat-web-client-@project.version@.jar, \
@@ -9,18 +8,22 @@
           thermostat-agent-command-@project.version@.jar, \
           thermostat-agent-cli-@project.version@.jar, \
           thermostat-thread-collector-@project.version@.jar, \
-          jetty-continuation-8.1.5.v20120716.jar, \
-          jetty-http-8.1.5.v20120716.jar, \
-          jetty-io-8.1.5.v20120716.jar, \
-          jetty-security-8.1.5.v20120716.jar, \
-          jetty-server-8.1.5.v20120716.jar, \
-          jetty-servlet-8.1.5.v20120716.jar, \
-          jetty-util-8.1.5.v20120716.jar, \
-          jetty-webapp-8.1.5.v20120716.jar, \
-          jetty-xml-8.1.5.v20120716.jar, \
+          commons-fileupload-@fileupload.version@.jar, \
+          commons-io-@commons-io.version@.jar, \
           httpcore-osgi-@httpcomponents.version@.jar, \
           httpclient-osgi-@httpcomponents.version@.jar, \
-          commons-fileupload-@fileupload.version@.jar
+          gson.jar, \
+          jetty-continuation.jar, \
+          jetty-http.jar, \
+          jetty-io.jar, \
+          jetty-security.jar, \
+          jetty-server.jar, \
+          jetty-servlet.jar, \
+          jetty-util.jar, \
+          jetty-webapp.jar, \
+          jetty-xml.jar, \
+          javax-servlet.jar, \
+          netty.jar
 
 description = starts and stops the thermostat storage and agent
 
--- a/distribution/config/commands/show-heap-histogram.properties	Fri Oct 26 13:13:42 2012 +0200
+++ b/distribution/config/commands/show-heap-histogram.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -2,9 +2,9 @@
           thermostat-client-core-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
           thermostat-client-command-@project.version@.jar, \
-          thermostat-client-heapdumper-@project.version@.jar, \
-          thermostat-swing-components-@project.version@.jar, \
-          thermostat-laf-@project.version@.jar
+          thermostat-client-heapdumper-core-@project.version@.jar, \
+          thermostat-laf-@project.version@.jar, \
+          netty.jar
 
 description = show the heap histogram
 
--- a/distribution/config/commands/storage.properties	Fri Oct 26 13:13:42 2012 +0200
+++ b/distribution/config/commands/storage.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -3,7 +3,8 @@
           thermostat-common-core-@project.version@.jar, \
           thermostat-agent-cli-@project.version@.jar, \
           thermostat-common-command-@project.version@.jar, \
-          thermostat-agent-command-@project.version@.jar
+          thermostat-agent-command-@project.version@.jar, \
+          netty.jar
 
 description = starts and stops the thermostat storage
 
@@ -31,4 +32,4 @@
 quiet.long = quiet
 quiet.hasarg = false
 quiet.required = false
-quiet.description = don't produce any output
\ No newline at end of file
+quiet.description = don't produce any output
--- a/distribution/config/osgi-export.properties	Fri Oct 26 13:13:42 2012 +0200
+++ b/distribution/config/osgi-export.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -33,15 +33,6 @@
 # to do so, delete this exception statement from your version.
 
 # OSGi public API
-com.mongodb
-com.mongodb.gridfs
-org.apache.commons.cli=1.2.0
-org.apache.commons.beanutils=1.8.3
-org.apache.commons.io
-org.apache.commons.io.output
-org.apache.commons.logging=1.1.1
-org.bson
-org.bson.types
 org.jfree.chart
 org.jfree.chart.axis
 org.jfree.chart.event
@@ -65,39 +56,6 @@
 com.sun.tools.attach
 com.sun.management
 
-jline=2.5.0
-jline.console=2.5.0
-jline.console.history=2.5.0
 sun.jvmstat
 sun.jvmstat.monitor
 sun.jvmstat.monitor.event
-
-org.jboss.netty=3.2.4.Final
-org.jboss.netty.bootstrap=3.2.4.Final
-org.jboss.netty.buffer=3.2.4.Final
-org.jboss.netty.channel=3.2.4.Final
-org.jboss.netty.channel.group=3.2.4.Final
-org.jboss.netty.channel.socket.nio=3.2.4.Final
-org.jboss.netty.handler.codec.frame=3.2.4.Final
-
-org.apache.lucene.analysis
-org.apache.lucene.document
-org.apache.lucene.index
-org.apache.lucene.search
-org.apache.lucene.store
-org.apache.lucene.util
-
-org.eclipse.jetty.server=8.1.0
-org.eclipse.jetty.server.handler=8.1.0
-org.eclipse.jetty.webapp=8.1.0
-org.eclipse.jetty.servlet=8.1.0
-org.eclipse.jetty.servlet.descriptor=8.1.0
-org.eclipse.jetty.continuation=8.1.0
-org.eclipse.jetty.http=8.1.0
-org.eclipse.jetty.io=8.1.0
-org.eclipse.jetty.security=8.1.0
-org.eclipse.jetty.util=8.1.0
-org.eclipse.jetty.xml=8.1.0
-javax.servlet=2.6.0
-javax.servlet.descriptor=2.6.0
-javax.servlet.http=2.6.0
--- a/distribution/pom.xml	Fri Oct 26 13:13:42 2012 +0200
+++ b/distribution/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -188,6 +188,55 @@
               <goal>run</goal>
             </goals>
           </execution>
+          <execution>
+            <id>version-less-dep-symlinks</id>
+            <phase>prepare-package</phase>
+            <configuration>
+              <target>
+                <symlink link="${project.build.directory}/libs/netty.jar"
+                         resource="${project.build.directory}/libs/netty-3.2.4.Final.jar" />
+                <symlink link="${project.build.directory}/libs/jline2.jar"
+                         resource="${project.build.directory}/libs/jline-2.9.jar" />
+                <symlink link="${project.build.directory}/libs/mongo.jar"
+                         resource="${project.build.directory}/libs/mongo-java-driver-2.7.3.jar" />
+                <symlink link="${project.build.directory}/libs/commons-cli.jar"
+                         resource="${project.build.directory}/libs/commons-cli-1.2.jar" />
+                <symlink link="${project.build.directory}/libs/commons-beanutils.jar"
+                         resource="${project.build.directory}/libs/commons-beanutils-1.8.3.jar" />
+                <symlink link="${project.build.directory}/libs/commons-collections.jar"
+                         resource="${project.build.directory}/libs/commons-collections-3.2.1.jar" />
+                <symlink link="${project.build.directory}/libs/commons-logging.jar"
+                         resource="${project.build.directory}/libs/com.springsource.org.apache.commons.logging-1.1.1.jar" />
+                <symlink link="${project.build.directory}/libs/lucene.jar"
+                         resource="${project.build.directory}/libs/org.apache.servicemix.bundles.lucene-3.6.0_1.jar" />
+                <symlink link="${project.build.directory}/libs/gson.jar"
+                         resource="${project.build.directory}/libs/gson-2.2.2.jar" />
+                <symlink link="${project.build.directory}/libs/jetty-continuation.jar"
+                         resource="${project.build.directory}/libs/jetty-continuation-8.1.5.v20120716.jar" />
+                <symlink link="${project.build.directory}/libs/jetty-http.jar"
+                         resource="${project.build.directory}/libs/jetty-http-8.1.5.v20120716.jar" />
+                <symlink link="${project.build.directory}/libs/jetty-io.jar"
+                         resource="${project.build.directory}/libs/jetty-io-8.1.5.v20120716.jar" />
+                <symlink link="${project.build.directory}/libs/jetty-security.jar"
+                         resource="${project.build.directory}/libs/jetty-security-8.1.5.v20120716.jar" />
+                <symlink link="${project.build.directory}/libs/jetty-server.jar"
+                         resource="${project.build.directory}/libs/jetty-server-8.1.5.v20120716.jar" />
+                <symlink link="${project.build.directory}/libs/jetty-servlet.jar"
+                         resource="${project.build.directory}/libs/jetty-servlet-8.1.5.v20120716.jar" />
+                <symlink link="${project.build.directory}/libs/jetty-util.jar"
+                         resource="${project.build.directory}/libs/jetty-util-8.1.5.v20120716.jar" />
+                <symlink link="${project.build.directory}/libs/jetty-webapp.jar"
+                         resource="${project.build.directory}/libs/jetty-webapp-8.1.5.v20120716.jar" />
+                <symlink link="${project.build.directory}/libs/jetty-xml.jar"
+                         resource="${project.build.directory}/libs/jetty-xml-8.1.5.v20120716.jar" />
+                <symlink link="${project.build.directory}/libs/javax-servlet.jar"
+                         resource="${project.build.directory}/libs/javax.servlet-3.0.0.v201112011016.jar" />
+              </target>
+            </configuration>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
         </executions>
       </plugin>
     </plugins>
@@ -249,7 +298,7 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-client-core</artifactId>
+      <artifactId>thermostat-client-swing</artifactId>
       <version>${project.version}</version>
     </dependency>
     <dependency>
@@ -259,17 +308,17 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-client-vmclassstat</artifactId>
+      <artifactId>thermostat-client-vmclassstat-swing</artifactId>
       <version>${project.version}</version>
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-osgi-memory-stats-panel</artifactId>
+      <artifactId>thermostat-osgi-memory-stats-panel-swing</artifactId>
       <version>${project.version}</version>
     </dependency>
     <dependency>
         <groupId>com.redhat.thermostat</groupId>
-        <artifactId>thermostat-osgi-living-vm-filter</artifactId>
+        <artifactId>thermostat-osgi-living-vm-filter-swing</artifactId>
         <version>${project.version}</version>
     </dependency>
     <dependency>
@@ -298,9 +347,9 @@
       <version>${project.version}</version>
     </dependency>
     <dependency>
-    	<groupId>com.redhat.thermostat</groupId>
-    	<artifactId>thermostat-killvm-client-swing</artifactId>
-    	<version>${project.version}</version>
+        <groupId>com.redhat.thermostat</groupId>
+        <artifactId>thermostat-killvm-client-swing</artifactId>
+        <version>${project.version}</version>
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
@@ -313,14 +362,14 @@
       <version>${project.version}</version>
     </dependency>
     <dependency>
-    	<groupId>com.redhat.thermostat</groupId>
-    	<artifactId>thermostat-osgi-process-handler</artifactId>
-    	<version>${project.version}</version>
+        <groupId>com.redhat.thermostat</groupId>
+        <artifactId>thermostat-osgi-process-handler</artifactId>
+        <version>${project.version}</version>
     </dependency>
     <dependency>
-    	<groupId>com.redhat.thermostat</groupId>
-    	<artifactId>thermostat-client-heapdumper</artifactId>
-    	<version>${project.version}</version>
+        <groupId>com.redhat.thermostat</groupId>
+        <artifactId>thermostat-client-heapdumper-swing</artifactId>
+        <version>${project.version}</version>
     </dependency>
     <dependency>
         <groupId>com.redhat.thermostat</groupId>
@@ -329,11 +378,6 @@
     </dependency>
     <dependency>
         <groupId>com.redhat.thermostat</groupId>
-        <artifactId>thermostat-swing-components</artifactId>
-        <version>${project.version}</version>
-    </dependency>
-    <dependency>
-        <groupId>com.redhat.thermostat</groupId>
         <artifactId>thermostat-keyring</artifactId>
         <version>${project.version}</version>
     </dependency>
--- a/distribution/scripts/thermostat-init-layout	Fri Oct 26 13:13:42 2012 +0200
+++ b/distribution/scripts/thermostat-init-layout	Fri Oct 26 15:32:56 2012 +0200
@@ -50,31 +50,55 @@
     THERMOSTAT_AGENT_RUN="${THERMOSTAT_HOME}/agent/run"
     THEMROSTAT_CLIENT="${THERMOSTAT_HOME}/client"
     THERMOSTAT_LIBS="${THERMOSTAT_HOME}/libs/native"
+    THERMOSTAT_OSGI_CACHE="${THERMOSTAT_HOME}/osgi-cache"
 
-    echo "creating $THERMOSTAT_STORAGE"
-    mkdir -p $THERMOSTAT_STORAGE
+    if [ ! -d "${THERMOSTAT_STORAGE}" ] ; then
+        echo "creating ${THERMOSTAT_STORAGE}"
+        mkdir -p ${THERMOSTAT_STORAGE}
+    fi
     
-    echo "creating $THERMOSTAT_LOG"
-    mkdir -p $THERMOSTAT_LOG
+    if [ ! -d "${THERMOSTAT_LOG}" ] ; then
+        echo "creating ${THERMOSTAT_LOG}"
+        mkdir -p ${THERMOSTAT_LOG}
+    fi
     
-    echo "creating $THERMOSTAT_PID"
-    mkdir -p $THERMOSTAT_PID
+    if [ ! -d "${THERMOSTAT_PID}" ] ; then
+        echo "creating ${THERMOSTAT_PID}"
+        mkdir -p ${THERMOSTAT_PID}
+    fi
     
-    echo "creating $THERMOSTAT_BACKEND"
-    mkdir -p $THERMOSTAT_BACKEND
+    if [ ! -d "${THERMOSTAT_BACKEND}" ] ; then
+        echo "creating ${THERMOSTAT_BACKEND}"
+        mkdir -p ${THERMOSTAT_BACKEND}
+    fi
     
-    echo "creating $THERMOSTAT_BIN"
-    mkdir -p $THERMOSTAT_BIN
+    if [ ! -e "${THERMOSTAT_BIN}" ] ; then
+        echo "creating ${THERMOSTAT_BIN}"
+        mkdir -p ${THERMOSTAT_BIN}
+    fi
     
-    echo "creating $THERMOSTAT_AGENT_LOG"
-    mkdir -p $THERMOSTAT_AGENT_LOG
+    if [ ! -d "${THERMOSTAT_AGENT_LOG}" ] ; then
+        echo "creating ${THERMOSTAT_AGENT_LOG}"
+        mkdir -p ${THERMOSTAT_AGENT_LOG}
+    fi
     
-    echo "creating $THERMOSTAT_AGENT_RUN"
-    mkdir -p $THERMOSTAT_AGENT_RUN
+    if [ ! -d "${THERMOSTAT_AGENT_RUN}" ] ; then
+        echo "creating ${THERMOSTAT_AGENT_RUN}"
+        mkdir -p ${THERMOSTAT_AGENT_RUN}
+    fi
+
+    if [ ! -d "${THERMOSTAT_CLIENT}" ] ; then
+        echo "creating ${THERMOSTAT_CLIENT}"
+        mkdir -p "${THERMOSTAT_CLIENT}"
+    fi
 
-    echo "creating $THERMOSTAT_CLIENT"
-    mkdir -p "$THERMOSTAT_CLIENT"
+    if [ ! -d "${THERMOSTAT_LIBS}" ] ; then
+        echo "creating ${THERMOSTAT_LIBS}"
+        mkdir -p ${THERMOSTAT_LIBS}
+    fi
 
-    echo "creating $THERMOSTAT_LIBS"
-    mkdir -p $THERMOSTAT_LIBS
+    if [ ! -d "${THERMOSTAT_OSGI_CACHE}" ] ; then
+        echo "creating ${THERMOSTAT_OSGI_CACHE}"
+        mkdir -p ${THERMOSTAT_OSGI_CACHE}
+    fi
 fi
--- a/eclipse/README.building	Fri Oct 26 13:13:42 2012 +0200
+++ b/eclipse/README.building	Fri Oct 26 15:32:56 2012 +0200
@@ -2,6 +2,8 @@
 # for all of mvn commands below.
 cd path/to/thermostat/home
 mvn clean install
+mvn -f eclipse/jfreechart-bundle-wrapping/pom.xml clean install
+mvn -f eclipse/jfreechart-p2-repository/pom.xml clean package
 mvn -f eclipse/test-deps-bundle-wrapping/pom.xml clean install
 mvn -f eclipse/test-deps-p2-repository/pom.xml clean package
 mvn -f eclipse/pom.xml clean package
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.client.feature/.project	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>com.redhat.thermostat.client.feature</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.pde.FeatureBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.FeatureNature</nature>
+	</natures>
+</projectDescription>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.client.feature/build.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,1 @@
+bin.includes = feature.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.client.feature/feature.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+      id="com.redhat.thermostat.client.feature"
+      label="Thermostat Client Feature"
+      version="0.5.0.qualifier"
+      provider-name="Red Hat Inc.">
+
+   <description url="http://icedtea.classpath.org/thermostat">
+      Plug-ins necessary for a Thermostat client interface.
+   </description>
+
+   <copyright url="http://icedtea.classpath.org/thermostat">
+      Copyright 2012 Red Hat, Inc.
+   </copyright>
+
+   <license url="http://www.gnu.org/licenses/">
+      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
+&lt;http://www.gnu.org/licenses/&gt;.
+
+Linking this code with other modules is making a combined work
+based on this code.  Thus, the terms and conditions of the GNU
+General Public License cover the whole combination.
+
+As a special exception, the copyright holders of this code give
+you permission to link this code with independent modules to
+produce an executable, regardless of the license terms of these
+independent modules, and to copy and distribute the resulting
+executable under terms of your choice, provided that you also
+meet, for each linked independent module, the terms and conditions
+of the license of that module.  An independent module is a module
+which is not derived from or based on this code.  If you modify
+this code, you may extend this exception to your version of the
+library, but you are not obligated to do so.  If you do not wish
+to do so, delete this exception statement from your version.
+   </license>
+
+   <plugin
+         id="com.redhat.thermostat.client.core"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="com.redhat.thermostat.common.core"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="com.redhat.thermostat.keyring"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="com.redhat.thermostat.bundles.org.jfree.chart"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="com.redhat.thermostat.bundles.org.jfree"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="com.redhat.thermostat.web.client"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="com.redhat.thermostat.web.common"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.apache.servicemix.bundles.lucene"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="com.google.gson"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="com.redhat.thermostat.launcher"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="com.redhat.thermostat.bundles.core"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+</feature>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.client.feature/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>thermostat-eclipse-parent</artifactId>
+    <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+  <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+  <artifactId>com.redhat.thermostat.client.feature</artifactId>
+  <version>0.5.0-SNAPSHOT</version>
+
+  <name>Thermostat Client Feature</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-client-core</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-web-client</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-web-common</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-launcher</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+     <!-- workaround for https://issues.sonatype.org/browse/TYCHO-168 -->
+     <resources>
+      <resource>
+        <directory>src</directory>
+        <excludes>
+          <exclude>**/*.java</exclude>
+        </excludes>
+      </resource>
+    </resources>
+    <plugins>
+      <plugin>
+        <groupId>org.eclipse.tycho</groupId>
+        <artifactId>tycho-source-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.eclipse.tycho</groupId>
+        <artifactId>tycho-packaging-plugin</artifactId>
+        <version>${tycho-version}</version>
+        <configuration>
+          <deployableFeature>true</deployableFeature>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <packaging>eclipse-feature</packaging>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/.classpath	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src/"/>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/.project	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>com.redhat.thermostat.eclipse.chart.common</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/META-INF/MANIFEST.MF	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,38 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Thermostat Eclipse Charting
+Bundle-SymbolicName: com.redhat.thermostat.eclipse.chart.common;singleton:=true
+Bundle-Version: 0.5.0.qualifier
+Bundle-Activator: com.redhat.thermostat.eclipse.chart.common.Activator
+Bundle-Vendor: Red Hat Inc.
+Bundle-RequiredExecutionEnvironment: JavaSE-1.7
+Import-Package: com.redhat.thermostat.client.core.views,
+ com.redhat.thermostat.client.locale,
+ com.redhat.thermostat.client.osgi.service,
+ com.redhat.thermostat.client.ui,
+ com.redhat.thermostat.common,
+ com.redhat.thermostat.common.appctx,
+ com.redhat.thermostat.common.dao,
+ com.redhat.thermostat.common.heap,
+ com.redhat.thermostat.common.locale,
+ com.redhat.thermostat.common.model,
+ com.redhat.thermostat.common.storage,
+ com.redhat.thermostat.common.utils,
+ com.redhat.thermostat.eclipse,
+ com.redhat.thermostat.eclipse.model,
+ com.redhat.thermostat.eclipse.views,
+ org.jfree.chart,
+ org.jfree.chart.axis,
+ org.jfree.chart.event,
+ org.jfree.chart.plot,
+ org.jfree.chart.renderer.xy,
+ org.jfree.data,
+ org.jfree.data.general,
+ org.jfree.data.time,
+ org.jfree.data.xy,
+ org.jfree.util,
+ org.osgi.framework;version="1.3.0"
+Bundle-ActivationPolicy: lazy
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime;bundle-version="3.8.0"
+Export-Package: com.redhat.thermostat.eclipse.chart.common
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/build.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/plugin.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+   <extension
+         point="org.eclipse.ui.views">
+      <view
+            allowMultiple="false"
+            category="com.redhat.thermostat.eclipse.main"
+            class="com.redhat.thermostat.eclipse.chart.common.HostCpuViewPart"
+            id="com.redhat.thermostat.eclipse.chart.hostCpuView"
+            name="Host CPU"
+            restorable="true">
+      </view>
+      <view
+            allowMultiple="false"
+            category="com.redhat.thermostat.eclipse.main"
+            class="com.redhat.thermostat.eclipse.chart.common.HostMemoryViewPart"
+            id="com.redhat.thermostat.eclipse.chart.hostMemoryView"
+            name="Host Memory"
+            restorable="true">
+      </view>
+      <view
+            category="com.redhat.thermostat.eclipse.main"
+            class="com.redhat.thermostat.eclipse.chart.common.VmCpuViewPart"
+            id="com.redhat.thermostat.eclipse.chart.vmCpuView"
+            name="VM CPU"
+            restorable="true">
+      </view>
+      <view
+            allowMultiple="false"
+            category="com.redhat.thermostat.eclipse.main"
+            class="com.redhat.thermostat.eclipse.chart.common.VmGcViewPart"
+            id="com.redhat.thermostat.eclipse.chart.vmGcView"
+            name="VM GC"
+            restorable="true">
+      </view>
+   </extension>
+
+</plugin>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>thermostat-eclipse-parent</artifactId>
+    <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+  <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+  <artifactId>com.redhat.thermostat.eclipse.chart.common</artifactId>
+  <packaging>eclipse-plugin</packaging>
+  <version>0.5.0-SNAPSHOT</version>
+
+  <name>Thermostat Eclipse Charting</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+      <artifactId>com.redhat.thermostat.eclipse</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+      <artifactId>com.redhat.thermostat.eclipse.jfreechart-repo</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+      <type>pom</type>
+    </dependency>
+  </dependencies>
+
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/Activator.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,89 @@
+/*
+ * 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.eclipse.chart.common;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+import com.redhat.thermostat.client.core.views.HostCpuViewProvider;
+import com.redhat.thermostat.client.core.views.HostMemoryViewProvider;
+import com.redhat.thermostat.client.core.views.VmCpuViewProvider;
+import com.redhat.thermostat.client.core.views.VmGcViewProvider;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+
+public class Activator extends AbstractUIPlugin {
+
+    // The plug-in ID
+    public static final String PLUGIN_ID = "com.redhat.thermostat.eclipse.chart.common"; //$NON-NLS-1$
+
+    private static Activator plugin;
+  
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext
+     * )
+     */
+    public void start(BundleContext context) throws Exception {
+        super.start(context);
+        plugin = this;
+        
+        // Register our ViewProviders
+        OSGIUtils.getInstance().registerService(HostCpuViewProvider.class, new SWTHostCpuViewProvider());
+        OSGIUtils.getInstance().registerService(HostMemoryViewProvider.class, new SWTHostMemoryViewProvider());
+        OSGIUtils.getInstance().registerService(VmCpuViewProvider.class, new SWTVmCpuViewProvider());
+        OSGIUtils.getInstance().registerService(VmGcViewProvider.class, new SWTVmGcViewProvider());
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext
+     * )
+     */
+    public void stop(BundleContext context) throws Exception {
+        plugin = null;
+        super.stop(context);
+    }
+    
+    public static Activator getDefault() {
+        return plugin;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/ChartUtils.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.eclipse.chart.common;
+
+import java.util.concurrent.CountDownLatch;
+
+import org.eclipse.ui.PlatformUI;
+
+public class ChartUtils {
+    
+    /**
+     * Executes runnable in the SWT UI thread after the necessary
+     * controls are created.
+     * @param latch - blocks runnable until count is zero
+     * @param runnable - task to execute
+     */
+    public static void runAfterCreated(CountDownLatch latch, Runnable runnable) {
+        try {
+            latch.await();
+            PlatformUI.getWorkbench().getDisplay().syncExec(runnable);
+        } catch (InterruptedException e) {
+            // Restore interrupted status
+            Thread.currentThread().interrupt();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/HostCpuViewPart.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,70 @@
+/*
+ * 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.eclipse.chart.common;
+
+import com.redhat.thermostat.client.core.views.HostCpuViewProvider;
+import com.redhat.thermostat.client.ui.HostCpuController;
+import com.redhat.thermostat.common.dao.CpuStatDAO;
+import com.redhat.thermostat.common.dao.HostInfoDAO;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.eclipse.views.SWTComponent;
+
+public class HostCpuViewPart extends HostRefViewPart {
+
+    private HostCpuController cpuController;
+
+    @Override
+    protected void createControllerView(HostRef ref) {
+        HostInfoDAO hostInfoDao = OSGIUtils.getInstance().getService(
+                HostInfoDAO.class);
+        CpuStatDAO cpuStatDao = OSGIUtils.getInstance().getService(
+                CpuStatDAO.class);
+        HostCpuViewProvider viewProvider = OSGIUtils.getInstance().getService(
+                HostCpuViewProvider.class);
+        cpuController = createController(hostInfoDao, cpuStatDao, ref,
+                viewProvider);
+        SWTComponent view = (SWTComponent) cpuController.getView();
+        view.createControl(top);
+    }
+
+    public HostCpuController createController(HostInfoDAO hostInfoDao,
+            CpuStatDAO cpuStatDao, HostRef ref, HostCpuViewProvider viewProvider) {
+        return new HostCpuController(hostInfoDao, cpuStatDao, ref, viewProvider);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/HostMemoryViewPart.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,72 @@
+/*
+ * 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.eclipse.chart.common;
+
+import com.redhat.thermostat.client.core.views.HostMemoryViewProvider;
+import com.redhat.thermostat.client.ui.HostMemoryController;
+import com.redhat.thermostat.common.dao.HostInfoDAO;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.MemoryStatDAO;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.eclipse.views.SWTComponent;
+
+public class HostMemoryViewPart extends HostRefViewPart {
+
+    private HostMemoryController controller;
+
+    @Override
+    protected void createControllerView(HostRef ref) {
+        HostInfoDAO hostInfoDao = OSGIUtils.getInstance().getService(
+                HostInfoDAO.class);
+        MemoryStatDAO memoryStatDao = OSGIUtils.getInstance().getService(
+                MemoryStatDAO.class);
+        HostMemoryViewProvider viewProvider = OSGIUtils.getInstance()
+                .getService(HostMemoryViewProvider.class);
+        controller = createController(hostInfoDao, memoryStatDao, ref,
+                viewProvider);
+        SWTComponent view = (SWTComponent) controller.getView();
+        view.createControl(top);
+    }
+
+    public HostMemoryController createController(HostInfoDAO hostInfoDao,
+            MemoryStatDAO memoryStatDao, HostRef ref,
+            HostMemoryViewProvider viewProvider) {
+        return new HostMemoryController(hostInfoDao, memoryStatDao, ref,
+                viewProvider);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/HostRefViewPart.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.eclipse.chart.common;
+
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.VmRef;
+
+public abstract class HostRefViewPart extends RefViewPart<HostRef> {
+
+    public HostRefViewPart() {
+        super();
+    }
+
+    @Override
+    protected HostRef getRefFromSelection(Object selection) {
+        HostRef ref = null;
+        if (selection instanceof HostRef) {
+            ref = (HostRef) selection;
+        }
+        else if (selection instanceof VmRef) {
+            ref = ((VmRef) selection).getAgent();
+        }
+        return ref;
+    }
+
+    @Override
+    protected String getNoSelectionMessage() {
+        return "No host selected";
+    }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/RecentTimeSeriesChartComposite.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,229 @@
+/*
+ * 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.eclipse.chart.common;
+
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowData;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.JFreeChart;
+
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.eclipse.ThermostatConstants;
+
+public class RecentTimeSeriesChartComposite extends Composite {
+    public static final String TEST_ID_UNIT_COMBO = "RecentTimeSeriesChartComposite.timeUnit";
+    public static final String TEST_ID_DURATION_TEXT = "RecentTimeSeriesChartComposite.timeDuration";
+    
+    private static final int MINIMUM_DRAW_SIZE = 100;
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private final RecentTimeSeriesChartController controller;
+
+    private Composite labelContainer;
+    private Label label;
+    private Combo unitSelector;
+    private Text durationSelector;
+
+    public RecentTimeSeriesChartComposite(Composite parent, int style, JFreeChart chart) {
+        super(parent, style);
+        this.setLayout(new GridLayout());
+        this.controller = new RecentTimeSeriesChartController(this, chart);
+
+        final ChartPanel cp = controller.getChartComposite();
+
+        cp.setDisplayToolTips(false);
+        cp.setMouseZoomable(false);
+        cp.setPopupMenu(null);
+
+        /*
+         * 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.
+         */
+        cp.setMinimumDrawHeight(MINIMUM_DRAW_SIZE);
+        cp.setMaximumDrawHeight(Integer.MAX_VALUE);
+        cp.setMinimumDrawWidth(MINIMUM_DRAW_SIZE);
+        cp.setMaximumDrawWidth(Integer.MAX_VALUE);
+
+        getControlsAndAdditionalDisplay(this);
+    }
+
+    private Composite getControlsAndAdditionalDisplay(Composite parent) {
+        Composite container = new Composite(parent, SWT.NONE);
+        GridLayout containerLayout = new GridLayout(2, false);
+        containerLayout.marginHeight = 0;
+        container.setLayout(containerLayout);
+
+        getChartControls(container);
+        getAdditionalDataDisplay(container);
+
+        return container;
+    }
+
+    private Composite getChartControls(Composite parent) {
+        Composite container = new Composite(parent, SWT.NONE);
+        RowLayout topLayout = new RowLayout(SWT.HORIZONTAL);
+        topLayout.center = true;
+        topLayout.marginHeight = 0;
+        container.setLayout(topLayout);
+        
+        Label prompt = new Label(container, SWT.NONE);
+        prompt.setText(translator.localize(LocaleResources.CHART_DURATION_SELECTOR_LABEL));
+
+        durationSelector = new Text(container, SWT.BORDER);
+        durationSelector.setData(ThermostatConstants.TEST_TAG, TEST_ID_DURATION_TEXT);
+        // Make 5 chars wide
+        GC gc = new GC(durationSelector);
+        FontMetrics metrics = gc.getFontMetrics();
+        int width = metrics.getAverageCharWidth() * 5;
+        int height = metrics.getHeight();
+        gc.dispose();
+        durationSelector.setLayoutData(new RowData(computeSize(width, height)));
+        
+        unitSelector = new Combo(container, SWT.NONE);
+        unitSelector.setData(ThermostatConstants.TEST_TAG, TEST_ID_UNIT_COMBO);
+        TimeUnit[] units = controller.getTimeUnits();
+        for (TimeUnit unit : units) {
+            unitSelector.add(unit.toString());
+        }
+
+        int defaultValue = controller.getTimeValue();
+        TimeUnit defaultUnit = controller.getTimeUnit();
+
+        TimeUnitChangeListener timeUnitChangeListener = new TimeUnitChangeListener(controller, defaultValue, defaultUnit);
+
+        durationSelector.addModifyListener(timeUnitChangeListener);
+        unitSelector.addSelectionListener(timeUnitChangeListener);
+
+        durationSelector.setText(String.valueOf(defaultValue));
+        int defaultPos = Arrays.asList(units).indexOf(defaultUnit);
+        unitSelector.select(defaultPos);
+
+        return container;
+    }
+
+    private Composite getAdditionalDataDisplay(Composite parent) {
+        Composite top = new Composite(parent, SWT.NONE);
+        GridLayout topLayout = new GridLayout();
+        topLayout.marginHeight = 0;
+        top.setLayout(topLayout);
+        top.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+        labelContainer = new Composite(top, SWT.NONE);
+        return top;
+    }
+
+    public void setDataInformationLabel(final String text) {
+        PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+            @Override
+            public void run() {
+                if (label == null) {
+                    label = new Label(labelContainer, SWT.NONE);
+                }
+
+                label.setText(text);
+            }
+        });
+    }
+
+    private class TimeUnitChangeListener implements SelectionListener, ModifyListener {
+
+        private final RecentTimeSeriesChartController controller;
+        private int value;
+        private TimeUnit unit;
+
+        public TimeUnitChangeListener(RecentTimeSeriesChartController controller, int defaultValue, TimeUnit defaultUnit) {
+            this.controller = controller;
+            this.value = defaultValue;
+            this.unit = defaultUnit;
+        }
+
+        private void updateChartParameters() {
+            controller.setTime(value, unit);
+        }
+
+        @Override
+        public void modifyText(ModifyEvent e) {
+            if (durationSelector.equals(e.widget)) {
+                try {
+                    this.value = Integer.valueOf(durationSelector.getText());
+                    updateChartParameters();
+                } catch (NumberFormatException nfe) {
+                    // ignore
+                }
+            }
+        }
+
+        @Override
+        public void widgetSelected(SelectionEvent e) {
+            if (unitSelector.equals(e.widget)) {
+                int idx = unitSelector.getSelectionIndex();
+                if (idx >= 0) {
+                    unit = controller.getTimeUnits()[idx];
+                    updateChartParameters();
+                }
+            }
+        }
+
+        @Override
+        public void widgetDefaultSelected(SelectionEvent e) {
+            widgetSelected(e);
+        }
+    }
+    
+    public RecentTimeSeriesChartController getController() {
+        return controller;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/RecentTimeSeriesChartController.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,110 @@
+/*
+ * 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.eclipse.chart.common;
+
+import java.awt.Frame;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.awt.SWT_AWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.XYPlot;
+
+public class RecentTimeSeriesChartController {
+
+    private static final int DEFAULT_VALUE = 10;
+    private static final TimeUnit DEFAULT_UNIT = TimeUnit.MINUTES;
+
+    private JFreeChart chart;
+    private ChartPanel panel;
+    private int timeValue = DEFAULT_VALUE;
+    private TimeUnit timeUnit = DEFAULT_UNIT;
+
+    public RecentTimeSeriesChartController(Composite parent, JFreeChart chart) {
+        this.chart = chart;
+        Composite top = new Composite(parent, SWT.NONE | SWT.EMBEDDED);
+        top.setLayout(new GridLayout());
+        top.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+        Frame frame = SWT_AWT.new_Frame(top);
+        this.panel = new ChartPanel(chart, true);
+        frame.add(panel);
+
+        // instead of just disabling display of tooltips, disable their generation too
+        if (chart.getPlot() instanceof XYPlot) {
+            chart.getXYPlot().getRenderer().setBaseToolTipGenerator(null);
+        }
+
+        chart.getXYPlot().getDomainAxis().setAutoRange(true);
+        chart.getXYPlot().getDomainAxis().setFixedAutoRange(timeUnit.toMillis(timeValue));
+
+        chart.getXYPlot().getRangeAxis().setAutoRange(true);
+
+    }
+
+    public ChartPanel getChartComposite() {
+        return panel;
+    }
+
+    public TimeUnit[] getTimeUnits() {
+        return new TimeUnit[] { TimeUnit.DAYS, TimeUnit.HOURS, TimeUnit.MINUTES };
+    }
+
+    public int getTimeValue() {
+        return timeValue;
+    }
+
+    public TimeUnit getTimeUnit() {
+        return timeUnit;
+    }
+
+    public void setTime(int value, TimeUnit unit) {
+        this.timeValue = value;
+        this.timeUnit = unit;
+
+        updateChart();
+    }
+
+    private void updateChart() {
+        chart.getXYPlot().getDomainAxis().setAutoRange(true);
+        chart.getXYPlot().getDomainAxis().setFixedAutoRange(timeUnit.toMillis(timeValue));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/RefViewPart.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.eclipse.chart.common;
+
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.ViewPart;
+
+import com.redhat.thermostat.common.dao.Ref;
+import com.redhat.thermostat.eclipse.ThermostatConstants;
+import com.redhat.thermostat.eclipse.views.HostsVmsTreeViewPart;
+
+public abstract class RefViewPart<T extends Ref> extends ViewPart implements ISelectionListener {
+
+    protected Composite top;
+
+    private Composite parent;
+    private Object selectedElement;
+
+    public RefViewPart() {
+        super();
+    }
+
+    @Override
+    public void createPartControl(Composite parent) {
+        this.parent = parent;
+        
+        createComposite();
+        
+        getWorkbenchWindow().getSelectionService().addSelectionListener(this);
+        
+        // Check for an existing selection
+        boolean selected = false;
+        IViewPart part = getWorkbenchWindow().getActivePage().findView(ThermostatConstants.VIEW_ID_HOST_VM);
+        if (part != null && part instanceof HostsVmsTreeViewPart) {
+            ISelection selection = part.getSite().getSelectionProvider().getSelection();
+            if (selection instanceof IStructuredSelection) {
+                handleSelection(selection);
+                selected = true;
+            }
+        }
+        if (!selected) {
+            createNoSelectionLabel();
+        }
+    }
+
+    public void createNoSelectionLabel() {
+        Label noHost = new Label(top, SWT.NONE);
+        noHost.setText(getNoSelectionMessage());
+    }
+
+    public IWorkbenchWindow getWorkbenchWindow() {
+        return PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+    }
+    
+    @Override
+    public void setFocus() {
+        parent.setFocus();
+    }
+
+    protected abstract void createControllerView(T ref);
+    
+    protected abstract T getRefFromSelection(Object selection);
+    
+    protected abstract String getNoSelectionMessage();
+    
+    @Override
+    public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+        // We must have received createPartControl
+        if (parent != null && !parent.isDisposed()) {
+            // Check if a HostRef has been selected
+            if (part instanceof HostsVmsTreeViewPart) {
+                if (selection instanceof IStructuredSelection) {
+                    handleSelection(selection);
+                }
+            }
+        }
+    }
+
+    private void handleSelection(ISelection selection) {
+        Object previous = selectedElement;
+        selectedElement = ((IStructuredSelection) selection).getFirstElement();
+        if (selectedElement != previous) {
+            T ref = getRefFromSelection(selectedElement);
+            if (ref != null) {
+                // Replace the existing view
+                top.dispose();
+                createComposite();
+   
+                createControllerView(ref);
+   
+                parent.layout();
+            }
+        }
+    }
+
+    private void createComposite() {
+        top = new Composite(parent, SWT.NONE);
+        top.setLayout(new GridLayout());
+        top.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/SWTHostCpuView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,314 @@
+/*
+ * 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.eclipse.chart.common;
+
+import java.awt.Color;
+import java.awt.EventQueue;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.PlatformUI;
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.renderer.xy.XYItemRenderer;
+import org.jfree.data.time.FixedMillisecond;
+import org.jfree.data.time.RegularTimePeriod;
+import org.jfree.data.time.TimeSeries;
+import org.jfree.data.time.TimeSeriesCollection;
+
+import com.redhat.thermostat.client.core.views.HostCpuView;
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.ui.ChartColors;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
+import com.redhat.thermostat.eclipse.ThermostatConstants;
+import com.redhat.thermostat.eclipse.views.SWTComponent;
+
+public class SWTHostCpuView extends HostCpuView implements SWTComponent {
+    public static final String TEST_ID_CPU_MODEL = "SWTHostCpuView.cpuModel";
+    public static final String TEST_ID_CPU_COUNT = "SWTHostCpuView.cpuCount";
+    public static final String TEST_ID_LEGEND_ITEM = "SWTHostCpuView.legendItem";
+    
+    private static final String LEGEND_COLOUR_BLOCK = "\u2588";
+    private static final int H_INDENT = 20;
+    private static final int SPACER_WIDTH = 10;
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+    
+    private JFreeChart chart;
+    private TimeSeriesCollection datasetCollection;
+    private Label cpuModel;
+    private Label cpuCount;
+    
+    private final Map<Integer, TimeSeries> datasets;
+    private final Map<String, Color> colors;
+    private Composite chartTop;
+    private Composite legendTop;
+    private Composite parent;
+    private ViewVisibilityWatcher watcher;
+    private CountDownLatch latch;
+    
+    public SWTHostCpuView() {
+        datasetCollection = new TimeSeriesCollection();
+        datasets = new HashMap<Integer, TimeSeries>();
+        colors = new HashMap<String, Color>();
+        watcher = new ViewVisibilityWatcher(notifier);
+        chart = createCpuChart();
+        latch = new CountDownLatch(1);
+    }
+    
+    public void createControl(Composite parent) {
+        this.parent = parent;
+        
+        Label summaryLabel = new Label(parent, SWT.LEAD);
+        Font stdFont = summaryLabel.getFont();
+        Font boldFont = new Font(stdFont.getDevice(),
+                stdFont.getFontData()[0].getName(),
+                stdFont.getFontData()[0].getHeight(), SWT.BOLD);
+        
+        summaryLabel.setText(translator.localize(LocaleResources.HOST_CPU_SECTION_OVERVIEW));
+        summaryLabel.setFont(boldFont);
+        
+        Composite detailsTop = new Composite(parent, SWT.NONE);
+        detailsTop.setLayout(new GridLayout(3, false));
+
+        Label cpuModelLabel = new Label(detailsTop, SWT.TRAIL);
+        cpuModelLabel.setText(translator.localize(LocaleResources.HOST_INFO_CPU_MODEL));
+        GridData hIndentLayoutData = new GridData();
+        hIndentLayoutData.horizontalIndent = H_INDENT;
+        cpuModelLabel.setLayoutData(hIndentLayoutData);
+        
+        Label cpuModelSpacer = new Label(detailsTop, SWT.NONE);
+        cpuModelSpacer.setLayoutData(new GridData(SPACER_WIDTH, SWT.DEFAULT));
+        
+        cpuModel = new Label(detailsTop, SWT.LEAD);
+        cpuModel.setData(ThermostatConstants.TEST_TAG, TEST_ID_CPU_MODEL);
+        cpuModel.setText("Unknown");
+
+        Label cpuCountLabel = new Label(detailsTop, SWT.TRAIL);
+        cpuCountLabel.setText(translator.localize(LocaleResources.HOST_INFO_CPU_COUNT));
+        cpuCountLabel.setLayoutData(hIndentLayoutData);
+        
+        Label cpuCountSpacer = new Label(detailsTop, SWT.NONE);
+        cpuCountSpacer.setLayoutData(new GridData(SPACER_WIDTH, SWT.DEFAULT));
+        
+        cpuCount = new Label(detailsTop, SWT.LEAD);
+        cpuCount.setData(ThermostatConstants.TEST_TAG, TEST_ID_CPU_COUNT);
+        cpuCount.setText("Unknown");
+        
+        chartTop = new RecentTimeSeriesChartComposite(parent, SWT.NONE, chart);
+        chartTop.setLayout(new GridLayout());
+        chartTop.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+        
+        legendTop = new Composite(parent, SWT.NONE);
+        RowLayout legendLayout = new RowLayout(SWT.HORIZONTAL);
+        legendLayout.center = true;
+        legendLayout.wrap = false;
+        legendLayout.marginHeight = 0;
+        legendTop.setLayout(legendLayout);
+        
+        // Notify threads that controls are created
+        latch.countDown();
+        
+        // Don't start giving updates until controls are created
+        watcher.watch(parent, ThermostatConstants.VIEW_ID_HOST_CPU);
+    }
+
+    private JFreeChart createCpuChart() {
+        JFreeChart chart = ChartFactory.createTimeSeriesChart(null,
+                translator.localize(LocaleResources.HOST_CPU_USAGE_CHART_TIME_LABEL),
+                translator.localize(LocaleResources.HOST_CPU_USAGE_CHART_VALUE_LABEL),
+                datasetCollection, false, false, false);
+
+        chart.getPlot().setBackgroundPaint(new Color(255, 255, 255, 0));
+        chart.getPlot().setBackgroundImageAlpha(0.0f);
+        chart.getPlot().setOutlinePaint(new Color(0, 0, 0, 0));
+
+        return chart;
+    }
+
+    public void setCpuCount(final String count) {
+        PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+            @Override
+            public void run() {
+                if (!cpuCount.isDisposed()) {
+                    cpuCount.setText(count);
+                }
+            }
+        });
+    }
+
+    public void setCpuModel(final String model) {
+        PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+            @Override
+            public void run() {
+                if (!cpuModel.isDisposed()) {
+                    cpuModel.setText(model);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void addCpuUsageChart(final int cpuIndex, final String humanReadableName) {
+        EventQueue.invokeLater(new Runnable() {
+
+            @Override
+            public void run() {
+                TimeSeries series = new TimeSeries(humanReadableName);
+                Color color = ChartColors.getColor(colors.size());
+                colors.put(humanReadableName, color);
+
+                datasets.put(cpuIndex, series);
+                datasetCollection.addSeries(series);
+
+                updateColors();
+
+                addLegendItem(humanReadableName, color);
+            }
+        });
+    }
+
+    @Override
+    public void addCpuUsageData(final int cpuIndex, List<DiscreteTimeData<Double>> data) {
+        final ArrayList<DiscreteTimeData<Double>> copy = new ArrayList<>(data);
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                TimeSeries dataset = datasets.get(cpuIndex);
+                for (DiscreteTimeData<Double> timeData: copy) {
+                    RegularTimePeriod period = new FixedMillisecond(timeData.getTimeInMillis());
+                    if (dataset.getDataItem(period) == null) {
+                        dataset.add(period, timeData.getData(), false);
+                    }
+                }
+                dataset.fireSeriesChanged();
+            }
+        });
+    }
+
+    @Override
+    public void clearCpuUsageData() {
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                for (Iterator<Map.Entry<Integer, TimeSeries>> iter = datasets.entrySet().iterator(); iter.hasNext();) {
+                    Map.Entry<Integer, TimeSeries> entry = iter.next();
+                    datasetCollection.removeSeries(entry.getValue());
+                    entry.getValue().clear();
+
+                    iter.remove();
+
+                }
+                updateColors();
+            }
+        });
+    }
+    
+    /**
+     * Adding or removing series to the series collection may change the order
+     * of existing items. Plus the paint for the index is now out-of-date. So
+     * let's walk through all the series and set the right paint for those.
+     */
+    private void updateColors() {
+        XYItemRenderer itemRenderer = chart.getXYPlot().getRenderer();
+        for (int i = 0; i < datasetCollection.getSeriesCount(); i++) {
+            String tag = (String) datasetCollection.getSeriesKey(i);
+            Color color = colors.get(tag);
+            itemRenderer.setSeriesPaint(i, color);
+        }
+    }
+    
+    
+    private Composite createLabelWithLegend(Composite parent, String text, Color color) {
+        Composite top = new Composite(parent, SWT.NONE);
+        GridLayout topLayout = new GridLayout(2, false);
+        topLayout.marginHeight = 0;
+        top.setLayout(topLayout);
+        
+        Label colourBlock = new Label(top, SWT.NONE);
+        colourBlock.setText(LEGEND_COLOUR_BLOCK);
+        
+        // Convert to SWT colour
+        final org.eclipse.swt.graphics.Color swtColour = new org.eclipse.swt.graphics.Color(
+                PlatformUI.getWorkbench().getDisplay(), color.getRed(),
+                color.getGreen(), color.getBlue());
+        colourBlock.addDisposeListener(new DisposeListener() {
+
+            @Override
+            public void widgetDisposed(DisposeEvent e) {
+                swtColour.dispose();
+            }
+        });
+        colourBlock.setForeground(swtColour);
+        
+        Label colourText = new Label(top, SWT.NONE);
+        colourText.setData(ThermostatConstants.TEST_TAG, TEST_ID_LEGEND_ITEM);
+        colourText.setText(text);
+        return top;
+    }
+    
+    private void addLegendItem(final String humanReadableName, final Color color) {
+        // We need to wait for the controls to be fully constructed
+        // before modifying the legend
+        ChartUtils.runAfterCreated(latch, new Runnable() {
+            @Override
+            public void run() {
+                createLabelWithLegend(legendTop, humanReadableName,
+                        color);
+                parent.layout();
+            }
+        });
+    }
+    
+    public JFreeChart getChart() {
+        return chart;
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/SWTHostCpuViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.eclipse.chart.common;
+
+import com.redhat.thermostat.client.core.views.HostCpuView;
+import com.redhat.thermostat.client.core.views.HostCpuViewProvider;
+
+public class SWTHostCpuViewProvider implements HostCpuViewProvider {
+
+    @Override
+    public HostCpuView createView() {
+        return new SWTHostCpuView();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/SWTHostMemoryView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,400 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.eclipse.chart.common;
+
+import java.awt.Color;
+import java.awt.EventQueue;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CountDownLatch;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.PlatformUI;
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.renderer.xy.XYItemRenderer;
+import org.jfree.data.time.FixedMillisecond;
+import org.jfree.data.time.RegularTimePeriod;
+import org.jfree.data.time.TimeSeries;
+import org.jfree.data.time.TimeSeriesCollection;
+
+import com.redhat.thermostat.client.core.views.HostMemoryView;
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.ui.ChartColors;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
+import com.redhat.thermostat.common.utils.DisplayableValues;
+import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
+import com.redhat.thermostat.eclipse.ThermostatConstants;
+import com.redhat.thermostat.eclipse.views.SWTComponent;
+
+public class SWTHostMemoryView extends HostMemoryView implements SWTComponent {
+    public static final String TEST_ID_TOTAL_MEM = "SWTHostMemoryView.totalMemory";
+    public static final String TEST_ID_LEGEND_ITEM_LABEL = "SWTHostMemoryView.legendItemLabel";
+    public static final String TEST_ID_LEGEND_ITEM_CHECKBOX = "SWTHostMemoryView.legendItemCheckbox";
+    
+    private static final String LEGEND_COLOUR_BLOCK = "\u2588";
+    private static final int H_INDENT = 20;
+    private static final int SPACER_WIDTH = 10;
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+    
+    private final TimeSeriesCollection memoryCollection;
+    private final Map<String, TimeSeries> dataset;
+    private final Map<String, Color> colors;
+    private final CopyOnWriteArrayList<GraphVisibilityChangeListener> listeners;
+    private final Map<String, Composite> checkboxes;
+    private final CountDownLatch latch;
+    
+    private Composite parent;
+    private Label totalMemory;
+    private ViewVisibilityWatcher watcher;
+    private JFreeChart chart;
+    private Composite legendTop;
+    
+    public SWTHostMemoryView() {
+        this.memoryCollection = new TimeSeriesCollection();
+        this.dataset = Collections.synchronizedMap(new HashMap<String, TimeSeries>());
+        this.colors = new HashMap<String, Color>();
+        this.listeners = new CopyOnWriteArrayList<GraphVisibilityChangeListener>();
+        this.checkboxes = new HashMap<String, Composite>();
+        this.watcher = new ViewVisibilityWatcher(notifier);
+        this.latch = new CountDownLatch(1);
+        this.chart = createMemoryChart();
+    }
+    
+    public void createControl(Composite parent) {
+        this.parent = parent;
+        
+        Label summaryLabel = new Label(parent, SWT.LEAD);
+        Font stdFont = summaryLabel.getFont();
+        Font boldFont = new Font(stdFont.getDevice(),
+                stdFont.getFontData()[0].getName(),
+                stdFont.getFontData()[0].getHeight(), SWT.BOLD);
+        
+        summaryLabel.setText(translator.localize(LocaleResources.HOST_MEMORY_SECTION_OVERVIEW));
+        summaryLabel.setFont(boldFont);
+        
+        Composite detailsTop = new Composite(parent, SWT.NONE);
+        detailsTop.setLayout(new GridLayout(3, false));
+        
+        Label cpuModelLabel = new Label(detailsTop, SWT.TRAIL);
+        cpuModelLabel.setText(translator.localize(LocaleResources.HOST_INFO_MEMORY_TOTAL));
+        GridData hIndentLayoutData = new GridData();
+        hIndentLayoutData.horizontalIndent = H_INDENT;
+        cpuModelLabel.setLayoutData(hIndentLayoutData);
+        
+        Label cpuModelSpacer = new Label(detailsTop, SWT.NONE);
+        cpuModelSpacer.setLayoutData(new GridData(SPACER_WIDTH, SWT.DEFAULT));
+        
+        totalMemory = new Label(detailsTop, SWT.LEAD);
+        totalMemory.setData(ThermostatConstants.TEST_TAG, TEST_ID_TOTAL_MEM);
+        totalMemory.setText("Unknown");
+        
+        Composite chartTop = new RecentTimeSeriesChartComposite(parent, SWT.NONE, chart);
+        chartTop.setLayout(new GridLayout());
+        chartTop.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+        
+        legendTop = new Composite(parent, SWT.NONE);
+        RowLayout legendLayout = new RowLayout(SWT.HORIZONTAL);
+        legendLayout.center = true;
+        legendLayout.wrap = false;
+        legendLayout.marginHeight = 0;
+        legendTop.setLayout(legendLayout);
+        
+        // Notify threads that controls are created
+        latch.countDown();
+        
+        // Don't start giving updates until controls are created
+        watcher.watch(parent, ThermostatConstants.VIEW_ID_HOST_MEMORY);
+    }
+
+    @Override
+    public void setTotalMemory(final String newValue) {
+        PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+            @Override
+            public void run() {
+                if (!totalMemory.isDisposed()) {
+                    totalMemory.setText(newValue);
+                }
+            }
+        });
+    }
+    
+    private JFreeChart createMemoryChart() {
+        // FIXME associate a fixed color with each type
+
+        JFreeChart chart = ChartFactory.createTimeSeriesChart(
+                null, // Title
+                translator.localize(LocaleResources.HOST_MEMORY_CHART_TIME_LABEL), // x-axis Label
+                translator.localize(LocaleResources.HOST_MEMORY_CHART_SIZE_LABEL, Scale.MiB.name()), // y-axis Label
+                memoryCollection, // Dataset
+                false, // Show Legend
+                false, // Use tooltips
+                false // Configure chart to generate URLs?
+                );
+
+        chart.getPlot().setBackgroundPaint( new Color(255,255,255,0) );
+        chart.getPlot().setBackgroundImageAlpha(0.0f);
+        chart.getPlot().setOutlinePaint(new Color(0,0,0,0));
+
+        NumberAxis rangeAxis = (NumberAxis) chart.getXYPlot().getRangeAxis();
+        rangeAxis.setAutoRangeMinimumSize(100);
+
+        return chart;
+    }
+    
+    private void fireShowHideHandlers(boolean show, String tag) {
+        for (GraphVisibilityChangeListener listener: listeners) {
+            if (show) {
+                listener.show(tag);
+            } else {
+                listener.hide(tag);
+            }
+        }
+    }
+    
+    @Override
+    public void addMemoryChart(final String tag, final String humanReadableName) {
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                int colorIndex = colors.size();
+                colors.put(tag, ChartColors.getColor(colorIndex));
+                TimeSeries series = new TimeSeries(tag);
+                dataset.put(tag, series);
+
+                addLegendItem(tag, humanReadableName);
+                
+                updateColors();
+            }
+        });
+    }
+
+    @Override
+    public void removeMemoryChart(final String tag) {
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                TimeSeries series = dataset.remove(tag);
+                memoryCollection.removeSeries(series);
+                
+                removeLegendItem(tag);
+
+                updateColors();
+            }
+        });
+    }
+
+    @Override
+    public void showMemoryChart(final String tag) {
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                TimeSeries series = dataset.get(tag);
+                memoryCollection.addSeries(series);
+
+                updateColors();
+            }
+        });
+    }
+
+    @Override
+    public void hideMemoryChart(final String tag) {
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                TimeSeries series = dataset.get(tag);
+                memoryCollection.removeSeries(series);
+
+                updateColors();
+            }
+        });
+    }
+
+    @Override
+    public void addMemoryData(final String tag, List<DiscreteTimeData<? extends Number>> data) {
+        final List<DiscreteTimeData<? extends Number>> copy = new ArrayList<>(data);
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                final TimeSeries series = dataset.get(tag);
+                for (DiscreteTimeData<? extends Number> timeData: copy) {
+                    RegularTimePeriod period = new FixedMillisecond(timeData.getTimeInMillis());
+                    if (series.getDataItem(period) == null) {
+                        Long sizeInBytes = (Long) timeData.getData();
+                        Double sizeInMegaBytes = DisplayableValues.Scale.convertTo(Scale.MiB, sizeInBytes);
+                        series.add(new FixedMillisecond(timeData.getTimeInMillis()), sizeInMegaBytes, false);
+                    }
+                }
+                series.fireSeriesChanged();
+            }
+        });
+    }
+
+    @Override
+    public void clearMemoryData(final String tag) {
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                TimeSeries series = dataset.get(tag);
+                series.clear();
+            }
+        });
+    }
+    
+    @Override
+    public void addGraphVisibilityListener(GraphVisibilityChangeListener listener) {
+        listeners.add(listener);
+    }
+
+    @Override
+    public void removeGraphVisibilityListener(GraphVisibilityChangeListener listener) {
+        listeners.remove(listener);
+    }
+
+    /**
+     * Adding or removing series to the series collection may change the order
+     * of existing items. Plus the paint for the index is now out-of-date. So
+     * let's walk through all the series and set the right paint for those.
+     */
+    private void updateColors() {
+        XYItemRenderer itemRenderer = chart.getXYPlot().getRenderer();
+        for (int i = 0; i < memoryCollection.getSeriesCount(); i++) {
+            String tag = (String) memoryCollection.getSeriesKey(i);
+            Color color = colors.get(tag);
+            itemRenderer.setSeriesPaint(i, color);
+        }
+    }
+    
+    private Composite createLabelWithLegend(Composite parent, String text, Color color, final String tag) {
+        Composite top = new Composite(parent, SWT.NONE);
+        RowLayout topLayout = new RowLayout(SWT.HORIZONTAL);
+        topLayout.marginHeight = 0;
+        topLayout.center = true;
+        top.setLayout(topLayout);
+        
+        final Button checkBox = new Button(top, SWT.CHECK);
+        checkBox.setData(ThermostatConstants.TEST_TAG, TEST_ID_LEGEND_ITEM_CHECKBOX);
+        checkBox.addSelectionListener(new SelectionListener() {
+            
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                fireShowHideHandlers(checkBox.getSelection(), tag);
+            }
+            
+            @Override
+            public void widgetDefaultSelected(SelectionEvent e) {
+                widgetSelected(e);
+            }
+        });
+        checkBox.setSelection(true);
+        checkBox.setAlignment(SWT.RIGHT);
+        
+        Label colourBlock = new Label(top, SWT.NONE);
+        colourBlock.setText(LEGEND_COLOUR_BLOCK);
+        
+        // Convert to SWT colour
+        final org.eclipse.swt.graphics.Color swtColour = new org.eclipse.swt.graphics.Color(
+                PlatformUI.getWorkbench().getDisplay(), color.getRed(),
+                color.getGreen(), color.getBlue());
+        colourBlock.addDisposeListener(new DisposeListener() {
+
+            @Override
+            public void widgetDisposed(DisposeEvent e) {
+                swtColour.dispose();
+            }
+        });
+        colourBlock.setForeground(swtColour);
+        
+        Label colourText = new Label(top, SWT.NONE);
+        colourText.setData(ThermostatConstants.TEST_TAG, TEST_ID_LEGEND_ITEM_LABEL);
+        colourText.setText(text);
+        return top;
+    }
+
+    private void addLegendItem(final String tag, final String humanReadableName) {
+        // We need to wait for the controls to be fully constructed
+        // before modifying the legend
+        ChartUtils.runAfterCreated(latch, new Runnable() {
+            @Override
+            public void run() {
+                Composite checkbox = createLabelWithLegend(legendTop,
+                        humanReadableName, colors.get(tag), tag);
+                checkboxes.put(tag, checkbox);
+                parent.layout();
+            }
+        });
+    }
+
+    private void removeLegendItem(final String tag) {
+        // We need to wait for the controls to be fully constructed
+        // before modifying the legend
+        ChartUtils.runAfterCreated(latch, new Runnable() {
+            @Override
+            public void run() {
+                Composite checkbox = checkboxes.remove(tag);
+                checkbox.dispose();
+                parent.layout();
+            }
+        });
+    }
+    
+    public JFreeChart getChart() {
+        return chart;
+    }
+    
+    public TimeSeries getSeries(String tag) {
+        return dataset.get(tag);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/SWTHostMemoryViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.eclipse.chart.common;
+
+import com.redhat.thermostat.client.core.views.HostMemoryView;
+import com.redhat.thermostat.client.core.views.HostMemoryViewProvider;
+
+public class SWTHostMemoryViewProvider implements HostMemoryViewProvider {
+
+    @Override
+    public HostMemoryView createView() {
+        return new SWTHostMemoryView();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/SWTVmCpuView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.eclipse.chart.common;
+
+import java.awt.EventQueue;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.JFreeChart;
+import org.jfree.data.time.FixedMillisecond;
+import org.jfree.data.time.RegularTimePeriod;
+import org.jfree.data.time.TimeSeries;
+import org.jfree.data.time.TimeSeriesCollection;
+
+import com.redhat.thermostat.client.core.views.VmCpuView;
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
+import com.redhat.thermostat.eclipse.ThermostatConstants;
+import com.redhat.thermostat.eclipse.views.SWTComponent;
+
+public class SWTVmCpuView extends VmCpuView implements SWTComponent {
+    
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+    
+    private final TimeSeriesCollection data;
+    private final TimeSeries cpuTimeSeries;
+    
+    private JFreeChart chart;
+    private ViewVisibilityWatcher watcher;
+    
+    public SWTVmCpuView() {
+        data = new TimeSeriesCollection();
+        cpuTimeSeries = new TimeSeries("cpu-stats");
+        watcher = new ViewVisibilityWatcher(notifier);
+        chart = createCpuChart();
+        
+        data.addSeries(cpuTimeSeries);
+    }
+    
+    public void createControl(Composite parent) {
+        Composite chartTop = new RecentTimeSeriesChartComposite(parent, SWT.NONE, chart);
+        chartTop.setLayout(new GridLayout());
+        chartTop.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+        
+        watcher.watch(parent, ThermostatConstants.VIEW_ID_VM_CPU);
+    }
+
+    private JFreeChart createCpuChart() {
+        JFreeChart chart = ChartFactory.createTimeSeriesChart(
+                null,
+                translator.localize(LocaleResources.VM_CPU_CHART_TIME_LABEL),
+                translator.localize(LocaleResources.VM_CPU_CHART_LOAD_LABEL),
+                data,
+                false, false, false);
+
+        chart.getXYPlot().getRangeAxis().setLowerBound(0.0);
+
+        return chart;
+    }
+    
+    @Override
+    public void addData(List<DiscreteTimeData<? extends Number>> data) {
+        final List<DiscreteTimeData<? extends Number>> copy = new ArrayList<>(data);
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                for (DiscreteTimeData<? extends Number> data: copy) {
+                    RegularTimePeriod period = new FixedMillisecond(data.getTimeInMillis());
+                    if (cpuTimeSeries.getDataItem(period) == null) {
+                        cpuTimeSeries.add(period, data.getData(), false);
+                    }
+                }
+                cpuTimeSeries.fireSeriesChanged();
+            }
+        });
+    }
+
+    @Override
+    public void clearData() {
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                cpuTimeSeries.clear();
+            }
+        });
+    }
+    
+    public JFreeChart getChart() {
+        return chart;
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/SWTVmCpuViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.eclipse.chart.common;
+
+import com.redhat.thermostat.client.core.views.VmCpuView;
+import com.redhat.thermostat.client.core.views.VmCpuViewProvider;
+
+public class SWTVmCpuViewProvider implements VmCpuViewProvider {
+
+    @Override
+    public VmCpuView createView() {
+        return new SWTVmCpuView();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/SWTVmGcView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,269 @@
+/*
+ * 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.eclipse.chart.common;
+
+import java.awt.EventQueue;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+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.event.ChartProgressEvent;
+import org.jfree.chart.event.ChartProgressListener;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.StandardXYBarPainter;
+import org.jfree.chart.renderer.xy.XYBarRenderer;
+import org.jfree.data.RangeType;
+import org.jfree.data.xy.IntervalXYDataset;
+
+import com.redhat.thermostat.client.core.views.VmGcView;
+import com.redhat.thermostat.client.locale.LocaleResources;
+import com.redhat.thermostat.client.ui.SampledDataset;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.model.IntervalTimeData;
+import com.redhat.thermostat.eclipse.ThermostatConstants;
+import com.redhat.thermostat.eclipse.views.SWTComponent;
+
+public class SWTVmGcView extends VmGcView implements SWTComponent {
+    
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+    
+    private final Map<String, SampledDataset> dataset;
+    private final Map<String, Composite> subPanels;
+    private final Map<String, JFreeChart> charts;
+    
+    private ViewVisibilityWatcher watcher;
+    private Composite parent;
+    private final CountDownLatch latch;
+
+    public SWTVmGcView() {
+        dataset = new HashMap<String, SampledDataset>();
+        subPanels = Collections.synchronizedMap(new HashMap<String, Composite>());
+        watcher = new ViewVisibilityWatcher(notifier);
+        latch = new CountDownLatch(1);
+        charts = new HashMap<String, JFreeChart>();
+    }
+
+    @Override
+    public void createControl(Composite parent) {
+        this.parent = parent;
+        
+        // Notify threads that controls are created
+        latch.countDown();
+        
+        // Don't start giving updates until controls are created
+        watcher.watch(parent, ThermostatConstants.VIEW_ID_VM_GC);
+    }
+
+    @Override
+    public void addChart(final String tag, final String title, final String units) {
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                SampledDataset newData = new SampledDataset();
+                dataset.put(tag, newData);
+                Composite subPanel = createCollectorDetailsPanel(tag, newData, title, units);
+                subPanels.put(tag, subPanel);
+            }
+        });
+    }
+
+    @Override
+    public void removeChart(final String tag) {
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                dataset.remove(tag);
+                charts.remove(tag);
+                Composite subPanel = subPanels.remove(tag);
+                destroyChartComposite(subPanel);
+            }
+        });
+    }
+
+    @Override
+    public void addData(final String tag, List<IntervalTimeData<Double>> data) {
+        final List<IntervalTimeData<Double>> copy = new ArrayList<>(data);
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                SampledDataset series = dataset.get(tag);
+                for (IntervalTimeData<Double> timeData: copy) {
+                    series.add(timeData.getStartTimeInMillis(), timeData.getEndTimeInMillis(), timeData.getData());
+                }
+                series.fireSeriesChanged();
+            }
+        });
+    }
+
+    @Override
+    public void clearData(final String tag) {
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                SampledDataset series = dataset.get(tag);
+                series.clear();
+            }
+        });
+    }
+    
+    private Composite createCollectorDetailsPanel(String tag, IntervalXYDataset collectorData, final String title, String units) {
+        // Create chart
+        final JFreeChart chart = ChartFactory.createHistogram(
+            null,
+            translator.localize(LocaleResources.VM_GC_COLLECTOR_CHART_REAL_TIME_LABEL),
+            translator.localize(LocaleResources.VM_GC_COLLECTOR_CHART_GC_TIME_LABEL, units),
+            collectorData,
+            PlotOrientation.VERTICAL,
+            false,
+            false,
+            false);
+
+        ((XYBarRenderer)(chart.getXYPlot().getRenderer())).setBarPainter(new StandardXYBarPainter());
+
+        setupPlotAxes(chart.getXYPlot());
+
+        chart.getXYPlot().setDomainCrosshairLockedOnData(true);
+        chart.getXYPlot().setDomainCrosshairVisible(true);
+
+        // An array so we can modify it in the UI thread
+        final Composite detailsTop[] = new Composite[1];
+        
+        // We need to wait for the controls to be fully constructed
+        // before adding the chart to the composite
+        ChartUtils.runAfterCreated(latch, new Runnable() {
+
+            @Override
+            public void run() {
+                detailsTop[0] = createChartComposite(title, chart);
+                parent.layout();
+            }
+        });
+        
+        charts.put(tag, chart);
+       
+        return detailsTop[0];
+    }
+    
+    private void setupPlotAxes(XYPlot plot) {
+        setupDomainAxis(plot);
+        setupRangeAxis(plot);
+    }
+
+    private void setupDomainAxis(XYPlot plot) {
+        plot.setDomainAxis(new DateAxis());
+    }
+
+    private void setupRangeAxis(XYPlot plot) {
+        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
+
+        rangeAxis.setRangeType(RangeType.POSITIVE);
+        rangeAxis.setAutoRange(true);
+        rangeAxis.setAutoRangeMinimumSize(1);
+    }
+
+    private Composite createChartComposite(final String title,
+            final JFreeChart chart) {
+        Composite detailsTop = new Composite(parent, SWT.NONE);
+        detailsTop.setLayout(new GridLayout());
+        detailsTop.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+        Label summaryLabel = new Label(detailsTop, SWT.LEAD);
+        Font stdFont = summaryLabel.getFont();
+        Font boldFont = new Font(stdFont.getDevice(),
+                stdFont.getFontData()[0].getName(),
+                stdFont.getFontData()[0].getHeight(), SWT.BOLD);
+
+        summaryLabel.setText(title);
+        summaryLabel.setFont(boldFont);
+
+        final RecentTimeSeriesChartComposite chartTop = new RecentTimeSeriesChartComposite(
+                detailsTop, SWT.NONE, chart);
+        chartTop.setLayout(new GridLayout());
+        chartTop.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+        chart.addProgressListener(new ChartProgressListener() {
+
+            @Override
+            public void chartProgress(ChartProgressEvent event) {
+                if (event.getType() != ChartProgressEvent.DRAWING_FINISHED) {
+                    return;
+                }
+
+                double rangeCrossHairValue = event.getChart().getXYPlot()
+                        .getRangeCrosshairValue();
+                chartTop.setDataInformationLabel(String
+                        .valueOf(rangeCrossHairValue));
+            }
+        });
+
+        return detailsTop;
+    }
+
+    private void destroyChartComposite(final Composite top) {
+        // We need to wait for the controls to be fully constructed
+        // before removing the chart from the composite
+        ChartUtils.runAfterCreated(latch, new Runnable() {
+
+            @Override
+            public void run() {
+                if (!parent.isDisposed()) {
+                    top.dispose();
+                    parent.layout();
+                }
+            }
+        });
+    }
+    
+    public JFreeChart getChart(String tag) {
+        return charts.get(tag);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/SWTVmGcViewProvider.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.eclipse.chart.common;
+
+import com.redhat.thermostat.client.core.views.VmGcView;
+import com.redhat.thermostat.client.core.views.VmGcViewProvider;
+
+public class SWTVmGcViewProvider implements VmGcViewProvider {
+
+    @Override
+    public VmGcView createView() {
+        return new SWTVmGcView();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/ViewVisibilityWatcher.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.eclipse.chart.common;
+
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IPartListener2;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+import com.redhat.thermostat.client.core.views.BasicView.Action;
+import com.redhat.thermostat.common.ActionNotifier;
+
+public class ViewVisibilityWatcher {
+    
+    private ActionNotifier<Action> notifier;
+    private boolean visible;
+
+    public ViewVisibilityWatcher(ActionNotifier<Action> notifier) {
+        this.notifier = notifier;
+        this.visible = false;
+    }
+    
+    public void watch(Composite parent, final String viewID) {
+        // Check if the view is currently visible
+        IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+        IViewPart chartView = activePage.findView(viewID);
+        if (activePage.isPartVisible(chartView)) {
+            visible = true;
+            notifier.fireAction(Action.VISIBLE);
+        }
+        
+        // Register listener for visibility updates on the Eclipse view
+        final IPartListener2 partListener = new IPartListener2() {
+            
+            @Override
+            public void partVisible(IWorkbenchPartReference partRef) {
+                // The workbench fires a visible event when the view first takes
+                // focus, even if it was already on top
+                if (!visible && viewID.equals(partRef.getId())) {
+                    notifier.fireAction(Action.VISIBLE);
+                    visible = true;
+                }
+            }
+            
+            @Override
+            public void partHidden(IWorkbenchPartReference partRef) {
+                if (visible && viewID.equals(partRef.getId())) {
+                    notifier.fireAction(Action.HIDDEN);
+                    visible = false;
+                }
+            }
+
+            @Override
+            public void partOpened(IWorkbenchPartReference partRef) {
+            }
+            
+            @Override
+            public void partInputChanged(IWorkbenchPartReference partRef) {
+            }
+            
+            @Override
+            public void partDeactivated(IWorkbenchPartReference partRef) {
+            }
+            
+            @Override
+            public void partClosed(IWorkbenchPartReference partRef) {
+            }
+            
+            @Override
+            public void partBroughtToTop(IWorkbenchPartReference partRef) {
+            }
+            
+            @Override
+            public void partActivated(IWorkbenchPartReference partRef) {
+            }
+        };
+        
+        PlatformUI.getWorkbench().getActiveWorkbenchWindow().getPartService().addPartListener(partListener);
+        
+        parent.addDisposeListener(new DisposeListener() {
+            
+            @Override
+            public void widgetDisposed(DisposeEvent e) {
+                PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
+                    
+                    @Override
+                    public void run() {
+                        IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+                        if (window != null) {
+                            window.getPartService().removePartListener(partListener);
+                        }
+                    }
+                });
+            }
+        });
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/VmCpuViewPart.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,66 @@
+/*
+ * 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.eclipse.chart.common;
+
+import com.redhat.thermostat.client.core.views.VmCpuViewProvider;
+import com.redhat.thermostat.client.ui.VmCpuController;
+import com.redhat.thermostat.common.dao.VmCpuStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.eclipse.views.SWTComponent;
+
+public class VmCpuViewPart extends VmRefViewPart {
+
+    private VmCpuController controller;
+
+    @Override
+    protected void createControllerView(VmRef ref) {
+        VmCpuStatDAO vmCpuStatDao = OSGIUtils.getInstance().getService(
+                VmCpuStatDAO.class);
+        VmCpuViewProvider viewProvider = OSGIUtils.getInstance().getService(
+                VmCpuViewProvider.class);
+        controller = createController(vmCpuStatDao, ref, viewProvider);
+        SWTComponent view = (SWTComponent) controller.getView();
+        view.createControl(top);
+    }
+
+    public VmCpuController createController(VmCpuStatDAO vmCpuStatDao,
+            VmRef ref, VmCpuViewProvider viewProvider) {
+        return new VmCpuController(vmCpuStatDao, ref, viewProvider);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/VmGcViewPart.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.eclipse.chart.common;
+
+import com.redhat.thermostat.client.core.views.VmGcViewProvider;
+import com.redhat.thermostat.client.ui.VmGcController;
+import com.redhat.thermostat.common.dao.VmGcStatDAO;
+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.eclipse.views.SWTComponent;
+
+public class VmGcViewPart extends VmRefViewPart {
+
+    private VmGcController controller;
+
+    @Override
+    protected void createControllerView(VmRef ref) {
+        VmMemoryStatDAO vmMemoryStatDao = OSGIUtils.getInstance().getService(
+                VmMemoryStatDAO.class);
+        VmGcStatDAO vmGcStatDao = OSGIUtils.getInstance().getService(
+                VmGcStatDAO.class);
+        VmGcViewProvider viewProvider = OSGIUtils.getInstance().getService(
+                VmGcViewProvider.class);
+        controller = createController(vmMemoryStatDao, vmGcStatDao, ref,
+                viewProvider);
+        SWTComponent view = (SWTComponent) controller.getView();
+        view.createControl(top);
+    }
+
+    public VmGcController createController(VmMemoryStatDAO vmMemoryStatDao,
+            VmGcStatDAO vmGcStatDao, VmRef ref, VmGcViewProvider viewProvider) {
+        return new VmGcController(vmMemoryStatDao, vmGcStatDao, ref,
+                viewProvider);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/VmRefViewPart.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.eclipse.chart.common;
+
+import com.redhat.thermostat.common.dao.VmRef;
+
+public abstract class VmRefViewPart extends RefViewPart<VmRef> {
+
+    public VmRefViewPart() {
+        super();
+    }
+
+    @Override
+    protected VmRef getRefFromSelection(Object selection) {
+        VmRef ref = null;
+        if (selection instanceof VmRef) {
+            ref = (VmRef) selection;
+        }
+        return ref;
+    }
+
+    @Override
+    protected String getNoSelectionMessage() {
+        return "No VM selected";
+    }
+
+}
--- a/eclipse/com.redhat.thermostat.eclipse.feature/feature.xml	Fri Oct 26 13:13:42 2012 +0200
+++ b/eclipse/com.redhat.thermostat.eclipse.feature/feature.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -13,48 +13,43 @@
    </copyright>
 
    <license url="http://www.gnu.org/licenses/">
-   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
-   &lt;http://www.gnu.org/licenses/&gt;.
-  
-   Linking this code with other modules is making a combined work
-   based on this code.  Thus, the terms and conditions of the GNU
-   General Public License cover the whole combination.
-  
-   As a special exception, the copyright holders of this code give
-   you permission to link this code with independent modules to
-   produce an executable, regardless of the license terms of these
-   independent modules, and to copy and distribute the resulting
-   executable under terms of your choice, provided that you also
-   meet, for each linked independent module, the terms and conditions
-   of the license of that module.  An independent module is a module
-   which is not derived from or based on this code.  If you modify
-   this code, you may extend this exception to your version of the
-   library, but you are not obligated to do so.  If you do not wish
-   to do so, delete this exception statement from your version.
+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
+&lt;http://www.gnu.org/licenses/&gt;.
+
+Linking this code with other modules is making a combined work
+based on this code.  Thus, the terms and conditions of the GNU
+General Public License cover the whole combination.
+
+As a special exception, the copyright holders of this code give
+you permission to link this code with independent modules to
+produce an executable, regardless of the license terms of these
+independent modules, and to copy and distribute the resulting
+executable under terms of your choice, provided that you also
+meet, for each linked independent module, the terms and conditions
+of the license of that module.  An independent module is a module
+which is not derived from or based on this code.  If you modify
+this code, you may extend this exception to your version of the
+library, but you are not obligated to do so.  If you do not wish
+to do so, delete this exception statement from your version.
    </license>
 
-   <!-- common core requires mongodb and lucene. Bundle names might need
-        patching for Fedora and other distros. They come from
-        eclipse.org's orbit repo -->
    <requires>
-      <import plugin="com.redhat.thermostat.common.core"/>
-      <import plugin="org.eclipse.orbit.mongodb" version="2.7.3" match="greaterOrEqual"/>
-      <import plugin="org.apache.lucene.core" version="3.5.0" match="greaterOrEqual"/>
+      <import feature="com.redhat.thermostat.client.feature" version="0.5.0.qualifier"/>
    </requires>
 
    <plugin
@@ -72,4 +67,11 @@
          fragment="true"
          unpack="false"/>
 
+   <plugin
+         id="com.redhat.thermostat.eclipse.chart.common"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
 </feature>
--- a/eclipse/com.redhat.thermostat.eclipse.feature/pom.xml	Fri Oct 26 13:13:42 2012 +0200
+++ b/eclipse/com.redhat.thermostat.eclipse.feature/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -15,8 +15,25 @@
 
   <dependencies>
     <dependency>
+      <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+      <artifactId>com.redhat.thermostat.eclipse</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <!-- using Web storage -->
+    <dependency>
       <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-common-core</artifactId>
+      <artifactId>thermostat-web-client</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-web-common</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <!-- DbService is in the launcher bundle -->
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-launcher</artifactId>
       <version>0.5.0-SNAPSHOT</version>
     </dependency>
   </dependencies>
--- a/eclipse/com.redhat.thermostat.eclipse.p2-repo/pom.xml	Fri Oct 26 13:13:42 2012 +0200
+++ b/eclipse/com.redhat.thermostat.eclipse.p2-repo/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -15,8 +15,25 @@
 
   <dependencies>
     <dependency>
+      <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+      <artifactId>com.redhat.thermostat.eclipse</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <!-- using Web storage -->
+    <dependency>
       <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-common-core</artifactId>
+      <artifactId>thermostat-web-client</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-web-common</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <!-- DbService is in the launcher bundle -->
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-launcher</artifactId>
       <version>0.5.0-SNAPSHOT</version>
     </dependency>
   </dependencies>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test.ui/.classpath	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src/"/>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test.ui/.project	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>com.redhat.thermostat.eclipse.test.ui</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test.ui/META-INF/MANIFEST.MF	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,37 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Thermostat Eclipse UI Tests
+Bundle-SymbolicName: com.redhat.thermostat.eclipse.test.ui
+Bundle-Version: 0.5.0.qualifier
+Bundle-Vendor: Red Hat Inc.
+Bundle-RequiredExecutionEnvironment: JavaSE-1.7
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.junit;bundle-version="4.10.0",
+ org.hamcrest;bundle-version="1.1.0"
+Import-Package: com.redhat.thermostat.client.core.views,
+ com.redhat.thermostat.client.osgi.service,
+ com.redhat.thermostat.client.ui,
+ com.redhat.thermostat.common,
+ com.redhat.thermostat.common.appctx,
+ com.redhat.thermostat.common.model,
+ com.redhat.thermostat.eclipse,
+ com.redhat.thermostat.eclipse.chart.common,
+ org.apache.log4j;version="1.2.13",
+ org.eclipse.swtbot.eclipse.finder,
+ org.eclipse.swtbot.eclipse.finder.matchers,
+ org.eclipse.swtbot.eclipse.finder.widgets,
+ org.eclipse.swtbot.swt.finder,
+ org.eclipse.swtbot.swt.finder.exceptions,
+ org.eclipse.swtbot.swt.finder.junit,
+ org.eclipse.swtbot.swt.finder.matchers,
+ org.eclipse.swtbot.swt.finder.utils,
+ org.eclipse.swtbot.swt.finder.waits,
+ org.eclipse.swtbot.swt.finder.widgets,
+ org.jfree.chart,
+ org.jfree.chart.axis,
+ org.jfree.chart.plot,
+ org.jfree.data.general,
+ org.jfree.data.time,
+ org.jfree.data.xy
+Export-Package: com.redhat.thermostat.eclipse.test.ui
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test.ui/build.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test.ui/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>thermostat-eclipse-parent</artifactId>
+    <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+  <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+  <artifactId>com.redhat.thermostat.eclipse.test.ui</artifactId>
+  <packaging>eclipse-test-plugin</packaging>
+  <version>0.5.0-SNAPSHOT</version>
+
+  <name>Thermostat Eclipse Client UI Tests</name>
+
+  <repositories>
+    <repository>
+      <id>swtbot</id>
+      <layout>p2</layout>
+      <url>http://download.eclipse.org/technology/swtbot/helios/dev-build/update-site</url>
+    </repository>
+  </repositories>
+
+  <dependencies>
+    <dependency>
+      <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+      <artifactId>com.redhat.thermostat.eclipse.chart.common</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+      <artifactId>com.redhat.thermostat.eclipse.test-deps-repo</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+      <type>pom</type>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.eclipse.tycho</groupId>
+        <artifactId>tycho-surefire-plugin</artifactId>
+        <version>${tycho-version}</version>
+        <configuration>
+          <useUIHarness>true</useUIHarness>
+          <useUIThread>false</useUIThread>
+          <product>org.eclipse.platform.ide</product>
+          <application>org.eclipse.ui.ide.workbench</application>
+          <bundleStartLevel>
+            <bundle>
+              <id>com.redhat.thermostat.common.core</id>
+              <level>4</level>
+              <autoStart>true</autoStart>
+            </bundle>
+            <bundle>
+              <id>com.redhat.thermostat.web.common</id>
+              <level>4</level>
+              <autoStart>true</autoStart>
+            </bundle>
+            <bundle>
+              <id>com.redhat.thermostat.web.client</id>
+              <level>4</level>
+              <autoStart>true</autoStart>
+            </bundle>
+            <bundle>
+              <id>com.redhat.thermostat.launcher</id>
+              <level>4</level>
+              <autoStart>true</autoStart>
+            </bundle>
+          </bundleStartLevel>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test.ui/src/com/redhat/thermostat/eclipse/test/ui/RecentTimeSeriesChartCompositeTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,220 @@
+/*
+ * 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.eclipse.test.ui;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot;
+import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner;
+import org.eclipse.swtbot.swt.finder.waits.DefaultCondition;
+import org.eclipse.swtbot.swt.finder.widgets.SWTBotCombo;
+import org.eclipse.swtbot.swt.finder.widgets.SWTBotText;
+import org.eclipse.swtbot.swt.finder.widgets.TimeoutException;
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.JFreeChart;
+import org.jfree.data.time.TimeSeriesCollection;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.redhat.thermostat.eclipse.ThermostatConstants;
+import com.redhat.thermostat.eclipse.chart.common.RecentTimeSeriesChartComposite;
+
+@RunWith(SWTBotJunit4ClassRunner.class)
+public class RecentTimeSeriesChartCompositeTest {
+    private SWTWorkbenchBot bot;
+    private Shell shell;
+    private JFreeChart chart;
+    private RecentTimeSeriesChartComposite composite;
+
+    @Before
+    public void beforeTest() throws Exception {
+        bot = new SWTWorkbenchBot();
+
+        Display.getDefault().syncExec(new Runnable() {
+
+            @Override
+            public void run() {
+                shell = new Shell(Display.getCurrent());
+                Composite parent = new Composite(shell, SWT.NONE);
+                parent.setLayout(new GridLayout());
+                parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
+                        true));
+
+                chart = createChart();
+                composite = new RecentTimeSeriesChartComposite(parent,
+                        SWT.NONE, chart);
+                shell.open();
+            }
+        });
+    }
+
+    private JFreeChart createChart() {
+        JFreeChart chart = ChartFactory.createTimeSeriesChart(null, null, null,
+                new TimeSeriesCollection(), false, false, false);
+        return chart;
+    }
+
+    @After
+    public void afterTest() throws Exception {
+        Display.getDefault().syncExec(new Runnable() {
+
+            @Override
+            public void run() {
+                if (shell != null) {
+                    shell.close();
+                }
+            }
+        });
+    }
+
+    @Test
+    public void testTimeUnitMinutes() throws Exception {
+        SWTBotCombo timeUnitCombo = bot.comboBoxWithId(
+                ThermostatConstants.TEST_TAG,
+                RecentTimeSeriesChartComposite.TEST_ID_UNIT_COMBO);
+        
+        List<TimeUnit> units = Arrays.asList(composite.getController().getTimeUnits());
+        timeUnitCombo.setSelection(units.indexOf(TimeUnit.MINUTES));
+        
+        checkTimeUnit(TimeUnit.MINUTES);
+    }
+    
+    @Test
+    public void testTimeUnitHours() throws Exception {
+        SWTBotCombo timeUnitCombo = bot.comboBoxWithId(
+                ThermostatConstants.TEST_TAG,
+                RecentTimeSeriesChartComposite.TEST_ID_UNIT_COMBO);
+        
+        List<TimeUnit> units = Arrays.asList(composite.getController().getTimeUnits());
+        timeUnitCombo.setSelection(units.indexOf(TimeUnit.HOURS));
+        
+        checkTimeUnit(TimeUnit.HOURS);
+    }
+    
+    @Test
+    public void testTimeUnitDays() throws Exception {
+        SWTBotCombo timeUnitCombo = bot.comboBoxWithId(
+                ThermostatConstants.TEST_TAG,
+                RecentTimeSeriesChartComposite.TEST_ID_UNIT_COMBO);
+        
+        List<TimeUnit> units = Arrays.asList(composite.getController().getTimeUnits());
+        timeUnitCombo.setSelection(units.indexOf(TimeUnit.DAYS));
+        
+        checkTimeUnit(TimeUnit.DAYS);
+    }
+    
+    @Test
+    public void testTimeDuration() throws Exception {
+        final int duration = 200;
+        SWTBotText durationText = bot.textWithId(ThermostatConstants.TEST_TAG,
+                RecentTimeSeriesChartComposite.TEST_ID_DURATION_TEXT);
+        
+        durationText.setText(String.valueOf(duration));
+        
+        checkTimeDuration(duration);
+    }
+    
+    @Test(expected = TimeoutException.class)
+    public void testTimeDurationBad() throws Exception {
+        final int duration = 200;
+        
+        // Set a proper duration value, then try a bad one
+        SWTBotText durationText = bot.textWithId(ThermostatConstants.TEST_TAG,
+                RecentTimeSeriesChartComposite.TEST_ID_DURATION_TEXT);
+        
+        durationText.setText(String.valueOf(duration));
+        
+        checkTimeDuration(duration);
+        
+        durationText.setText("Not an int");
+        
+        // Ensure duration unchanged
+        bot.waitWhile(new DefaultCondition() {
+            
+            @Override
+            public boolean test() throws Exception {
+                return composite.getController().getTimeValue() == duration;
+            }
+            
+            @Override
+            public String getFailureMessage() {
+                return "Success";
+            }
+        });
+    }
+
+    private void checkTimeDuration(final int duration) {
+        bot.waitUntil(new DefaultCondition() {
+            
+            @Override
+            public boolean test() throws Exception {
+                return composite.getController().getTimeValue() == duration;
+            }
+            
+            @Override
+            public String getFailureMessage() {
+                return "Duration not set";
+            }
+        });
+    }
+
+    private void checkTimeUnit(final TimeUnit unit) {
+        bot.waitUntil(new DefaultCondition() {
+            
+            @Override
+            public boolean test() throws Exception {
+                return unit.equals(composite.getController().getTimeUnit());
+            }
+            
+            @Override
+            public String getFailureMessage() {
+                return "Time unit not set to " + unit.toString();
+            }
+        });
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test.ui/src/com/redhat/thermostat/eclipse/test/ui/SWTHostCpuViewTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,335 @@
+/*
+ * 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.eclipse.test.ui;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot;
+import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner;
+import org.eclipse.swtbot.swt.finder.waits.DefaultCondition;
+import org.eclipse.swtbot.swt.finder.widgets.SWTBotLabel;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.data.time.TimeSeriesCollection;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.redhat.thermostat.common.model.DiscreteTimeData;
+import com.redhat.thermostat.eclipse.ThermostatConstants;
+import com.redhat.thermostat.eclipse.chart.common.SWTHostCpuView;
+
+@RunWith(SWTBotJunit4ClassRunner.class)
+public class SWTHostCpuViewTest {
+    private SWTWorkbenchBot bot;
+    private SWTHostCpuView view;
+    private Shell shell;
+
+    @Before
+    public void beforeTest() throws Exception {
+        bot = new SWTWorkbenchBot();
+        
+        Display.getDefault().syncExec(new Runnable() {
+
+            @Override
+            public void run() {
+                shell = new Shell(Display.getCurrent());
+                Composite parent = new Composite(shell, SWT.NONE);
+                parent.setLayout(new GridLayout());
+                parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
+                        true));
+                view = new SWTHostCpuView();
+                view.createControl(parent);
+                shell.open();
+            }
+        });
+    }
+
+    @After
+    public void afterTest() throws Exception {
+        Display.getDefault().syncExec(new Runnable() {
+
+            @Override
+            public void run() {
+                if (shell != null) {
+                    shell.close();
+                    view = null;
+                }
+            }
+        });
+    }
+
+    @Test
+    public void testSetCpuModel() throws Exception {
+        String model = "Test CPU";
+
+        view.setCpuModel(model);
+
+        bot.waitUntil(new DefaultCondition() {
+
+            @Override
+            public boolean test() throws Exception {
+                SWTBotLabel label = bot.labelWithId(
+                        ThermostatConstants.TEST_TAG,
+                        SWTHostCpuView.TEST_ID_CPU_MODEL);
+                return !label.getText().equals("Unknown"); // TODO Externalize
+            }
+
+            @Override
+            public String getFailureMessage() {
+                return "CPU Model label unchanged after set";
+            }
+
+        });
+    }
+
+    @Test
+    public void testSetCpuCount() throws Exception {
+        String count = "8";
+
+        view.setCpuCount(count);
+
+        bot.waitUntil(new DefaultCondition() {
+
+            @Override
+            public boolean test() throws Exception {
+                SWTBotLabel label = bot.labelWithId(
+                        ThermostatConstants.TEST_TAG,
+                        SWTHostCpuView.TEST_ID_CPU_COUNT);
+                return !label.getText().equals("Unknown"); // TODO Externalize
+            }
+
+            @Override
+            public String getFailureMessage() {
+                return "CPU Model label unchanged after set";
+            }
+
+        });
+    }
+
+    @Test
+    public void testAddCpuUsageChart() throws Exception {
+        String humanReadableName = "Test";
+
+        // Test series added
+        addSeries(0, humanReadableName, 1);
+
+        // Verify legend added
+        SWTBotLabel label = bot.labelWithId(ThermostatConstants.TEST_TAG,
+                SWTHostCpuView.TEST_ID_LEGEND_ITEM);
+        assertEquals(humanReadableName, label.getText());
+    }
+
+    private void addSeries(int seriesIndex, String humanReadableName,
+            final int numSeries) {
+        view.addCpuUsageChart(seriesIndex, humanReadableName);
+
+        bot.waitUntil(new DefaultCondition() {
+
+            @Override
+            public boolean test() throws Exception {
+                JFreeChart chart = view.getChart();
+                XYPlot plot = (XYPlot) chart.getPlot();
+                int count = plot.getSeriesCount();
+                return count == numSeries;
+            }
+
+            @Override
+            public String getFailureMessage() {
+                return "Data series never added";
+            }
+        });
+
+        // Wait until legend added
+        bot.labelWithId(ThermostatConstants.TEST_TAG,
+                SWTHostCpuView.TEST_ID_LEGEND_ITEM);
+    }
+
+    @Test
+    public void testAddCpuUsageChartMultiple() throws Exception {
+        String humanReadableName1 = "Test 1";
+        String humanReadableName2 = "Test 2";
+
+        addSeries(0, humanReadableName1, 1);
+        addSeries(1, humanReadableName2, 2);
+
+        // Verify legend added
+        SWTBotLabel label = bot.labelWithId(ThermostatConstants.TEST_TAG,
+                SWTHostCpuView.TEST_ID_LEGEND_ITEM, 0);
+        assertEquals(humanReadableName1, label.getText());
+        label = bot.labelWithId(ThermostatConstants.TEST_TAG,
+                SWTHostCpuView.TEST_ID_LEGEND_ITEM, 1);
+        assertEquals(humanReadableName2, label.getText());
+    }
+
+    @Test
+    public void testAddCpuUsageData() throws Exception {
+        List<DiscreteTimeData<Double>> data = new ArrayList<DiscreteTimeData<Double>>();
+
+        data.add(new DiscreteTimeData<Double>(1000L, 50D));
+        data.add(new DiscreteTimeData<Double>(2000L, 75D));
+        data.add(new DiscreteTimeData<Double>(3000L, 25D));
+
+        addSeries(0, "Test", 1);
+
+        addData(0, data);
+
+        JFreeChart chart = view.getChart();
+        TimeSeriesCollection dataset = (TimeSeriesCollection) chart.getXYPlot()
+                .getDataset();
+
+        assertEquals(1000L, dataset.getX(0, 0));
+        assertEquals(2000L, dataset.getX(0, 1));
+        assertEquals(3000L, dataset.getX(0, 2));
+
+        assertEquals(50D, dataset.getY(0, 0));
+        assertEquals(75D, dataset.getY(0, 1));
+        assertEquals(25D, dataset.getY(0, 2));
+    }
+
+    private void addData(final int seriesIndex,
+            final List<DiscreteTimeData<Double>> data) {
+        view.addCpuUsageData(seriesIndex, data);
+
+        bot.waitUntil(new DefaultCondition() {
+
+            @Override
+            public boolean test() throws Exception {
+                JFreeChart chart = view.getChart();
+                TimeSeriesCollection dataset = (TimeSeriesCollection) chart
+                        .getXYPlot().getDataset();
+                return dataset.getItemCount(seriesIndex) == data.size();
+            }
+
+            @Override
+            public String getFailureMessage() {
+                return "Data not added";
+            }
+        });
+    }
+
+    @Test
+    public void testAddCpuUsageDataMultiple() throws Exception {
+        List<DiscreteTimeData<Double>> data1 = new ArrayList<DiscreteTimeData<Double>>();
+
+        data1.add(new DiscreteTimeData<Double>(1000L, 50D));
+        data1.add(new DiscreteTimeData<Double>(2000L, 75D));
+        data1.add(new DiscreteTimeData<Double>(3000L, 25D));
+
+        List<DiscreteTimeData<Double>> data2 = new ArrayList<DiscreteTimeData<Double>>();
+
+        data2.add(new DiscreteTimeData<Double>(1500L, 30D));
+        data2.add(new DiscreteTimeData<Double>(2500L, 60D));
+        data2.add(new DiscreteTimeData<Double>(3500L, 90D));
+
+        addSeries(0, "Test 1", 1);
+        addSeries(1, "Test 2", 2);
+
+        addData(0, data1);
+        addData(1, data2);
+
+        JFreeChart chart = view.getChart();
+        TimeSeriesCollection dataset = (TimeSeriesCollection) chart.getXYPlot()
+                .getDataset();
+
+        assertEquals(1000L, dataset.getX(0, 0));
+        assertEquals(2000L, dataset.getX(0, 1));
+        assertEquals(3000L, dataset.getX(0, 2));
+
+        assertEquals(50D, dataset.getY(0, 0));
+        assertEquals(75D, dataset.getY(0, 1));
+        assertEquals(25D, dataset.getY(0, 2));
+
+        assertEquals(1500L, dataset.getX(1, 0));
+        assertEquals(2500L, dataset.getX(1, 1));
+        assertEquals(3500L, dataset.getX(1, 2));
+
+        assertEquals(30D, dataset.getY(1, 0));
+        assertEquals(60D, dataset.getY(1, 1));
+        assertEquals(90D, dataset.getY(1, 2));
+    }
+
+    @Test
+    public void testClearCpuUsageData() {
+        List<DiscreteTimeData<Double>> data1 = new ArrayList<DiscreteTimeData<Double>>();
+
+        data1.add(new DiscreteTimeData<Double>(1000L, 50D));
+        data1.add(new DiscreteTimeData<Double>(2000L, 75D));
+        data1.add(new DiscreteTimeData<Double>(3000L, 25D));
+
+        List<DiscreteTimeData<Double>> data2 = new ArrayList<DiscreteTimeData<Double>>();
+
+        data2.add(new DiscreteTimeData<Double>(1500L, 30D));
+        data2.add(new DiscreteTimeData<Double>(2500L, 60D));
+        data2.add(new DiscreteTimeData<Double>(3500L, 90D));
+
+        addSeries(0, "Test 1", 1);
+        addSeries(1, "Test 2", 2);
+
+        addData(0, data1);
+        addData(1, data2);
+
+        view.clearCpuUsageData();
+
+        // Wait until data cleared
+        bot.waitUntil(new DefaultCondition() {
+
+            @Override
+            public boolean test() throws Exception {
+                JFreeChart chart = view.getChart();
+                int count = chart.getXYPlot().getSeriesCount();
+                return count == 0;
+            }
+
+            @Override
+            public String getFailureMessage() {
+                return "Data not cleared";
+            }
+        });
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test.ui/src/com/redhat/thermostat/eclipse/test/ui/SWTHostMemoryViewTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,541 @@
+/*
+ * 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.eclipse.test.ui;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Widget;
+import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot;
+import org.eclipse.swtbot.swt.finder.exceptions.WidgetNotFoundException;
+import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner;
+import org.eclipse.swtbot.swt.finder.matchers.WithId;
+import org.eclipse.swtbot.swt.finder.utils.SWTBotPreferences;
+import org.eclipse.swtbot.swt.finder.waits.DefaultCondition;
+import org.eclipse.swtbot.swt.finder.widgets.SWTBotCheckBox;
+import org.eclipse.swtbot.swt.finder.widgets.SWTBotLabel;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.data.time.TimeSeries;
+import org.jfree.data.time.TimeSeriesCollection;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.redhat.thermostat.client.core.views.HostMemoryView.GraphVisibilityChangeListener;
+import com.redhat.thermostat.common.model.DiscreteTimeData;
+import com.redhat.thermostat.eclipse.ThermostatConstants;
+import com.redhat.thermostat.eclipse.chart.common.SWTHostMemoryView;
+
+@RunWith(SWTBotJunit4ClassRunner.class)
+public class SWTHostMemoryViewTest implements GraphVisibilityChangeListener {
+    private SWTWorkbenchBot bot;
+    private SWTHostMemoryView view;
+    private Shell shell;
+
+    @Before
+    public void beforeTest() throws Exception {
+        bot = new SWTWorkbenchBot();
+        
+        Display.getDefault().syncExec(new Runnable() {
+
+            @Override
+            public void run() {
+                shell = new Shell(Display.getCurrent());
+                Composite parent = new Composite(shell, SWT.NONE);
+                parent.setLayout(new GridLayout());
+                parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
+                        true));
+                view = new SWTHostMemoryView();
+                view.createControl(parent);
+                view.addGraphVisibilityListener(SWTHostMemoryViewTest.this);
+                shell.open();
+            }
+        });
+    }
+
+    @After
+    public void afterTest() throws Exception {
+        Display.getDefault().syncExec(new Runnable() {
+
+            @Override
+            public void run() {
+                if (shell != null) {
+                    shell.close();
+                    view = null;
+                }
+            }
+        });
+    }
+
+    @Test
+    public void testSetTotalMemory() throws Exception {
+        String totalMem = "8 GB";
+
+        view.setTotalMemory(totalMem);
+
+        bot.waitUntil(new DefaultCondition() {
+
+            @Override
+            public boolean test() throws Exception {
+                SWTBotLabel label = bot.labelWithId(ThermostatConstants.TEST_TAG,
+                        SWTHostMemoryView.TEST_ID_TOTAL_MEM);
+                return !label.getText().equals("Unknown"); // TODO Externalize
+            }
+
+            @Override
+            public String getFailureMessage() {
+                return "Total memory label unchanged after set";
+            }
+
+        });
+    }
+
+    @Test
+    public void testAddMemoryChart() throws Exception {
+        final String tag = "TEST";
+        String humanReadableName = "Test";
+
+        addSeries(tag, humanReadableName);
+
+        // Verify legend added
+        SWTBotLabel label = bot.labelWithId(ThermostatConstants.TEST_TAG,
+                SWTHostMemoryView.TEST_ID_LEGEND_ITEM_LABEL);
+        assertEquals(humanReadableName, label.getText());
+    }
+
+    @Test
+    public void testAddMemoryChartMultiple() throws Exception {
+        final String tag1 = "TEST1";
+        final String tag2 = "TEST2";
+        String humanReadableName1 = "Test 1";
+        String humanReadableName2 = "Test 2";
+
+        addSeries(tag1, humanReadableName1);
+        addSeries(tag2, humanReadableName2);
+
+        // Verify legend added
+        SWTBotLabel label = bot.labelWithId(ThermostatConstants.TEST_TAG,
+                SWTHostMemoryView.TEST_ID_LEGEND_ITEM_LABEL, 0);
+        assertEquals(humanReadableName1, label.getText());
+        label = bot.labelWithId(ThermostatConstants.TEST_TAG,
+                SWTHostMemoryView.TEST_ID_LEGEND_ITEM_LABEL, 1);
+        assertEquals(humanReadableName2, label.getText());
+    }
+
+    @Test
+    public void testRemoveMemoryChart() throws Exception {
+        final String tag = "TEST";
+        String humanReadableName = "Test";
+
+        addSeries(tag, humanReadableName);
+        
+        view.showMemoryChart(tag);
+        waitUntilSeriesShown(1);
+
+        view.removeMemoryChart(tag);
+
+        checkSeriesRemoved(tag, 0);
+
+        // Verify legend removed
+        checkLegendRemoved();
+    }
+
+    @Test
+    public void testRemoveMemoryChartMultiple() throws Exception {
+        final String tag1 = "TEST1";
+        final String tag2 = "TEST2";
+        String humanReadableName1 = "Test 1";
+        String humanReadableName2 = "Test 2";
+
+        addSeries(tag1, humanReadableName1);
+        addSeries(tag2, humanReadableName2);
+        
+        // Show both series
+        view.showMemoryChart(tag1);
+        waitUntilSeriesShown(1);
+
+        view.showMemoryChart(tag2);
+        waitUntilSeriesShown(2);
+
+        view.removeMemoryChart(tag2);
+
+        checkSeriesRemoved(tag2, 1);
+
+        // Verify legend removed
+        checkLegendItemRemoved(1);
+    }
+
+    private void checkSeriesRemoved(final String tag, final int numSeries) {
+        // Wait until series removed from chart and dataset
+        bot.waitUntil(new DefaultCondition() {
+
+            @Override
+            public boolean test() throws Exception {
+                JFreeChart chart = view.getChart();
+                XYPlot plot = chart.getXYPlot();
+                int count = plot.getSeriesCount();
+                return view.getSeries(tag) == null && count == numSeries;
+            }
+
+            @Override
+            public String getFailureMessage() {
+                return "Data series never removed";
+            }
+        });
+    }
+
+    private void checkLegendRemoved() {
+        bot.waitUntil(new DefaultCondition() {
+
+            @Override
+            public boolean test() throws Exception {
+                boolean result = false;
+
+                // Don't make this wait
+                long saveTimeout = SWTBotPreferences.TIMEOUT;
+                SWTBotPreferences.TIMEOUT = 0;
+                try {
+                    bot.widget(WithId.withId(ThermostatConstants.TEST_TAG,
+                            SWTHostMemoryView.TEST_ID_LEGEND_ITEM_LABEL));
+                } catch (WidgetNotFoundException e) {
+                    result = true;
+                }
+                SWTBotPreferences.TIMEOUT = saveTimeout;
+
+                return result;
+            }
+
+            @Override
+            public String getFailureMessage() {
+                return "Legend not removed";
+            }
+        });
+    }
+    
+    private void checkLegendItemRemoved(final int size) {
+        bot.waitUntil(new DefaultCondition() {
+
+            @Override
+            public boolean test() throws Exception {
+                List<? extends Widget> widgets = bot.widgets(WithId.withId(ThermostatConstants.TEST_TAG,
+                        SWTHostMemoryView.TEST_ID_LEGEND_ITEM_LABEL));
+                return widgets.size() == size;
+            }
+
+            @Override
+            public String getFailureMessage() {
+                return "Legend item not removed";
+            }
+        });
+    }
+
+    @Test
+    public void testHideMemoryChart() throws Exception {
+        String tag = "TEST";
+        String humanReadableName = "Test";
+
+        addSeries(tag, humanReadableName);
+        view.showMemoryChart(tag);
+
+        waitUntilSeriesShown(1);
+
+        // Click checkbox to trigger hideMemoryChart
+        SWTBotCheckBox checkbox = bot.checkBoxWithId(
+                ThermostatConstants.TEST_TAG,
+                SWTHostMemoryView.TEST_ID_LEGEND_ITEM_CHECKBOX);
+        checkbox.click();
+
+        // Wait until series hidden
+        waitUntilSeriesShown(0);
+    }
+
+    @Test
+    public void testShowMemoryChart() throws Exception {
+        String tag = "TEST";
+        String humanReadableName = "Test";
+
+        addSeries(tag, humanReadableName);
+        view.showMemoryChart(tag);
+
+        waitUntilSeriesShown(1);
+    }
+
+    @Test
+    public void testShowHiddenMemoryChart() throws Exception {
+        String tag = "TEST";
+        String humanReadableName = "Test";
+
+        addSeries(tag, humanReadableName);
+        view.showMemoryChart(tag);
+
+        waitUntilSeriesShown(1);
+
+        // Click checkbox to trigger hideMemoryChart
+        SWTBotCheckBox checkbox = bot.checkBoxWithId(
+                ThermostatConstants.TEST_TAG,
+                SWTHostMemoryView.TEST_ID_LEGEND_ITEM_CHECKBOX);
+        checkbox.click();
+
+        // Wait until series hidden
+        waitUntilSeriesShown(0);
+
+        // Click checkbox to trigger showMemoryChart
+        checkbox.click();
+
+        waitUntilSeriesShown(1);
+    }
+    
+    @Test
+    public void testAddMemoryData() throws Exception {
+        String tag = "TEST";
+        String humanReadableName = "Test";
+
+        addSeries(tag, humanReadableName);
+        view.showMemoryChart(tag);
+
+        waitUntilSeriesShown(1);
+        
+        // Add some test data
+        List<DiscreteTimeData<? extends Number>> data = new ArrayList<DiscreteTimeData<? extends Number>>();
+        data.add(new DiscreteTimeData<Long>(1000L, 134217728L)); // 128MiB
+        data.add(new DiscreteTimeData<Long>(2000L, 268435456L)); // 256MiB
+        data.add(new DiscreteTimeData<Long>(3000L, 536870912L)); // 512MiB
+        
+        final JFreeChart chart = view.getChart();
+        final TimeSeries series = view.getSeries(tag);
+        
+        addData(tag, data, series);
+        
+        TimeSeriesCollection dataset = (TimeSeriesCollection) chart.getXYPlot().getDataset();
+        int seriesIndex = chart.getXYPlot().getDataset().indexOf(series.getKey());
+        
+        assertEquals(1000L, dataset.getX(seriesIndex, 0));
+        assertEquals(2000L, dataset.getX(seriesIndex, 1));
+        assertEquals(3000L, dataset.getX(seriesIndex, 2));
+        
+        assertEquals(128D, dataset.getY(seriesIndex, 0));
+        assertEquals(256D, dataset.getY(seriesIndex, 1));
+        assertEquals(512D, dataset.getY(seriesIndex, 2));
+    }
+
+    private void addData(String tag,
+            final List<DiscreteTimeData<? extends Number>> data,
+            final TimeSeries series) {
+        view.addMemoryData(tag, data);
+
+        // Wait until data added to chart
+        bot.waitUntil(new DefaultCondition() {
+
+            @Override
+            public boolean test() throws Exception {
+                return series.getItemCount() == data.size();
+            }
+
+            @Override
+            public String getFailureMessage() {
+                return "Data never added";
+            }
+        });
+    }
+    
+    @Test
+    public void testAddMemoryDataMultiple() throws Exception {
+        String tag1 = "TEST1";
+        String tag2 = "TEST2";
+        String humanReadableName1 = "Test 1";
+        String humanReadableName2 = "Test 2";
+
+        addSeries(tag1, humanReadableName1);
+        view.showMemoryChart(tag1);
+        
+        addSeries(tag2, humanReadableName2);
+        view.showMemoryChart(tag2);
+
+        waitUntilSeriesShown(2);
+        
+        // Add some test data
+        List<DiscreteTimeData<? extends Number>> data1 = new ArrayList<DiscreteTimeData<? extends Number>>();
+        data1.add(new DiscreteTimeData<Long>(1000L, 134217728L)); // 128MiB
+        data1.add(new DiscreteTimeData<Long>(2000L, 268435456L)); // 256MiB
+        data1.add(new DiscreteTimeData<Long>(3000L, 536870912L)); // 512MiB
+        
+        List<DiscreteTimeData<? extends Number>> data2 = new ArrayList<DiscreteTimeData<? extends Number>>();
+        data2.add(new DiscreteTimeData<Long>(1500L, 536870912L)); // 512MiB
+        data2.add(new DiscreteTimeData<Long>(2500L, 134217728L)); // 128MiB
+        data2.add(new DiscreteTimeData<Long>(3500L, 268435456L)); // 256MiB
+        
+        final JFreeChart chart = view.getChart();
+        final TimeSeries series1 = view.getSeries(tag1);
+        final TimeSeries series2 = view.getSeries(tag2);
+        
+        addData(tag1, data1, series1);
+        addData(tag2, data2, series2);
+        
+        TimeSeriesCollection dataset = (TimeSeriesCollection) chart.getXYPlot().getDataset();
+        int series1Index = chart.getXYPlot().getDataset().indexOf(series1.getKey());
+        int series2Index = chart.getXYPlot().getDataset().indexOf(series2.getKey());
+        
+        assertEquals(1000L, dataset.getX(series1Index, 0));
+        assertEquals(2000L, dataset.getX(series1Index, 1));
+        assertEquals(3000L, dataset.getX(series1Index, 2));
+        
+        assertEquals(128D, dataset.getY(series1Index, 0));
+        assertEquals(256D, dataset.getY(series1Index, 1));
+        assertEquals(512D, dataset.getY(series1Index, 2));
+        
+        assertEquals(1500L, dataset.getX(series2Index, 0));
+        assertEquals(2500L, dataset.getX(series2Index, 1));
+        assertEquals(3500L, dataset.getX(series2Index, 2));
+        
+        assertEquals(512D, dataset.getY(series2Index, 0));
+        assertEquals(128D, dataset.getY(series2Index, 1));
+        assertEquals(256D, dataset.getY(series2Index, 2));
+    }
+    
+    @Test
+    public void testClearMemoryData() throws Exception {
+        String tag1 = "TEST1";
+        String tag2 = "TEST2";
+        String humanReadableName1 = "Test 1";
+        String humanReadableName2 = "Test 2";
+
+        addSeries(tag1, humanReadableName1);
+        view.showMemoryChart(tag1);
+        
+        addSeries(tag2, humanReadableName2);
+        view.showMemoryChart(tag2);
+
+        waitUntilSeriesShown(2);
+        
+        // Add some test data
+        List<DiscreteTimeData<? extends Number>> data1 = new ArrayList<DiscreteTimeData<? extends Number>>();
+        data1.add(new DiscreteTimeData<Long>(1000L, 134217728L)); // 128MiB
+        data1.add(new DiscreteTimeData<Long>(2000L, 268435456L)); // 256MiB
+        data1.add(new DiscreteTimeData<Long>(3000L, 536870912L)); // 512MiB
+        
+        List<DiscreteTimeData<? extends Number>> data2 = new ArrayList<DiscreteTimeData<? extends Number>>();
+        data2.add(new DiscreteTimeData<Long>(1500L, 536870912L)); // 512MiB
+        data2.add(new DiscreteTimeData<Long>(2500L, 134217728L)); // 128MiB
+        data2.add(new DiscreteTimeData<Long>(3500L, 268435456L)); // 256MiB
+        
+        final TimeSeries series1 = view.getSeries(tag1);
+        final TimeSeries series2 = view.getSeries(tag2);
+        
+        addData(tag1, data1, series1);
+        addData(tag2, data2, series2);
+        
+        // Remove data from series
+        view.clearMemoryData(tag1);
+        
+        // Wait until data removed to chart
+        bot.waitUntil(new DefaultCondition() {
+
+            @Override
+            public boolean test() throws Exception {
+                return series1.getItemCount() == 0;
+            }
+
+            @Override
+            public String getFailureMessage() {
+                return "Data never added";
+            }
+        });
+        
+        // Check other series' size
+        assertEquals(data2.size(), series2.getItemCount());
+    }
+
+    private void waitUntilSeriesShown(final int numSeries) {
+        bot.waitUntil(new DefaultCondition() {
+
+            @Override
+            public boolean test() throws Exception {
+                JFreeChart chart = view.getChart();
+                XYPlot plot = chart.getXYPlot();
+                int count = plot.getSeriesCount();
+                return count == numSeries;
+            }
+
+            @Override
+            public String getFailureMessage() {
+                return "Data series never shown/hidden";
+            }
+        });
+    }
+
+    private void addSeries(final String tag, String humanReadableName) {
+        view.addMemoryChart(tag, humanReadableName);
+
+        // Wait until series added
+        bot.waitUntil(new DefaultCondition() {
+
+            @Override
+            public boolean test() throws Exception {
+                return view.getSeries(tag) != null;
+            }
+
+            @Override
+            public String getFailureMessage() {
+                return "Data series never added";
+            }
+        });
+
+        // Wait for legend
+        bot.labelWithId(ThermostatConstants.TEST_TAG,
+                SWTHostMemoryView.TEST_ID_LEGEND_ITEM_LABEL);
+    }
+
+    @Override
+    public void show(String tag) {
+        view.showMemoryChart(tag);
+    }
+
+    @Override
+    public void hide(String tag) {
+        view.hideMemoryChart(tag);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test.ui/src/com/redhat/thermostat/eclipse/test/ui/SWTVmCpuViewTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.eclipse.test.ui;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot;
+import org.eclipse.swtbot.swt.finder.waits.DefaultCondition;
+import org.jfree.chart.JFreeChart;
+import org.jfree.data.xy.XYDataset;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.model.DiscreteTimeData;
+import com.redhat.thermostat.eclipse.chart.common.SWTVmCpuView;
+
+public class SWTVmCpuViewTest {
+    private SWTWorkbenchBot bot;
+    private SWTVmCpuView view;
+    private Shell shell;
+
+    @Before
+    public void beforeTest() throws Exception {
+        bot = new SWTWorkbenchBot();
+        
+        Display.getDefault().syncExec(new Runnable() {
+
+            @Override
+            public void run() {
+                shell = new Shell(Display.getCurrent());
+                Composite parent = new Composite(shell, SWT.NONE);
+                parent.setLayout(new GridLayout());
+                parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
+                        true));
+                view = new SWTVmCpuView();
+                view.createControl(parent);
+                shell.open();
+            }
+        });
+    }
+
+    @After
+    public void afterTest() throws Exception {
+        Display.getDefault().syncExec(new Runnable() {
+
+            @Override
+            public void run() {
+                if (shell != null) {
+                    shell.close();
+                    view = null;
+                }
+            }
+        });
+    }
+    
+    @Test
+    public void testAddData() {
+        List<DiscreteTimeData<? extends Number>> data = new ArrayList<DiscreteTimeData<? extends Number>>();
+        
+        data.add(new DiscreteTimeData<Number>(1000L, 20));
+        data.add(new DiscreteTimeData<Number>(2000L, 80));
+        data.add(new DiscreteTimeData<Number>(3000L, 50));
+        
+        addSeries(data);
+        
+        JFreeChart chart = view.getChart();
+        XYDataset dataset = chart.getXYPlot().getDataset();
+        assertEquals(1000L, dataset.getX(0, 0));
+        assertEquals(2000L, dataset.getX(0, 1));
+        assertEquals(3000L, dataset.getX(0, 2));
+        
+        assertEquals(20, dataset.getY(0, 0));
+        assertEquals(80, dataset.getY(0, 1));
+        assertEquals(50, dataset.getY(0, 2));
+    }
+
+    private void addSeries(List<DiscreteTimeData<? extends Number>> data) {
+        view.addData(data);
+        
+        bot.waitUntil(new DefaultCondition() {
+            
+            @Override
+            public boolean test() throws Exception {
+                JFreeChart chart = view.getChart();
+                return chart.getXYPlot().getDataset().getItemCount(0) == 3;
+            }
+            
+            @Override
+            public String getFailureMessage() {
+                return "Data never added";
+            }
+        });
+    }
+
+    @Test
+    public void testClearData() {
+        List<DiscreteTimeData<? extends Number>> data = new ArrayList<DiscreteTimeData<? extends Number>>();
+        
+        data.add(new DiscreteTimeData<Number>(1000L, 20));
+        data.add(new DiscreteTimeData<Number>(2000L, 80));
+        data.add(new DiscreteTimeData<Number>(3000L, 50));
+        
+        addSeries(data);
+        
+        view.clearData();
+        
+        bot.waitUntil(new DefaultCondition() {
+            
+            @Override
+            public boolean test() throws Exception {
+                JFreeChart chart = view.getChart();
+                return chart.getXYPlot().getDataset().getItemCount(0) == 0;
+            }
+            
+            @Override
+            public String getFailureMessage() {
+                return "Data never cleared";
+            }
+        });
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test.ui/src/com/redhat/thermostat/eclipse/test/ui/SWTVmGcViewTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,300 @@
+/*
+ * 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.eclipse.test.ui;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot;
+import org.eclipse.swtbot.swt.finder.waits.DefaultCondition;
+import org.jfree.chart.JFreeChart;
+import org.jfree.data.xy.IntervalXYDataset;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.model.IntervalTimeData;
+import com.redhat.thermostat.eclipse.chart.common.SWTVmGcView;
+
+public class SWTVmGcViewTest {
+    private SWTWorkbenchBot bot;
+    private SWTVmGcView view;
+    private Shell shell;
+
+    @Before
+    public void beforeTest() throws Exception {
+        bot = new SWTWorkbenchBot();
+        
+        Display.getDefault().syncExec(new Runnable() {
+
+            @Override
+            public void run() {
+                shell = new Shell(Display.getCurrent());
+                Composite parent = new Composite(shell, SWT.NONE);
+                parent.setLayout(new GridLayout());
+                parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
+                        true));
+                view = new SWTVmGcView();
+                view.createControl(parent);
+                shell.open();
+            }
+        });
+    }
+
+    @After
+    public void afterTest() throws Exception {
+        Display.getDefault().syncExec(new Runnable() {
+
+            @Override
+            public void run() {
+                if (shell != null) {
+                    shell.close();
+                    view = null;
+                }
+            }
+        });
+    }
+
+    @Test
+    public void testAddChart() {
+        addChart("TESTGC", "Test GC");
+    }
+
+    private void addChart(final String tag, String name) {
+        view.addChart(tag, name, "ms");
+        
+        bot.waitUntil(new DefaultCondition() {
+            
+            @Override
+            public boolean test() throws Exception {
+                return view.getChart(tag) != null;
+            }
+            
+            @Override
+            public String getFailureMessage() {
+                return "Chart not added";
+            }
+        });
+    }
+    
+    @Test
+    public void testAddChartMultiple() {
+        String tag = "TESTGC1";
+        addChart(tag, "Test GC 1");
+        addChart("TESTGC2", "Test GC 2");
+        
+        // Ensure first is still there
+        assertNotNull(view.getChart(tag));
+    }
+
+    @Test
+    public void testRemoveChart() {
+        final String tag1 = "TESTGC1";
+        addChart(tag1, "Test GC 1");
+        String tag2 = "TESTGC2";
+        addChart(tag2, "Test GC 2");
+        
+        view.removeChart(tag1);
+        
+        bot.waitUntil(new DefaultCondition() {
+            
+            @Override
+            public boolean test() throws Exception {
+                return view.getChart(tag1) == null;
+            }
+            
+            @Override
+            public String getFailureMessage() {
+                return "Chart not removed";
+            }
+        });
+        
+        // Ensure other chart still there
+        assertNotNull(view.getChart(tag2));
+    }
+
+    @Test
+    public void testAddData() {
+        final String tag = "TESTGC";
+        addChart(tag, "Test GC");
+        
+        List<IntervalTimeData<Double>> data = new ArrayList<IntervalTimeData<Double>>();
+        data.add(new IntervalTimeData<Double>(1000L, 1500L, 100D));
+        data.add(new IntervalTimeData<Double>(1500L, 2000L, 120D));
+        data.add(new IntervalTimeData<Double>(2000L, 2500L, 170D));
+        
+        addData(tag, data);
+        
+        JFreeChart chart = view.getChart(tag);
+        IntervalXYDataset dataset = (IntervalXYDataset) chart.getXYPlot().getDataset();
+        
+        assertEquals(1000L, dataset.getStartX(0, 0));
+        assertEquals(1500L, dataset.getEndX(0, 0));
+        assertEquals(100D, dataset.getY(0, 0));
+        
+        assertEquals(1500L, dataset.getStartX(0, 1));
+        assertEquals(2000L, dataset.getEndX(0, 1));
+        assertEquals(120D, dataset.getY(0, 1));
+        
+        assertEquals(2000L, dataset.getStartX(0, 2));
+        assertEquals(2500L, dataset.getEndX(0, 2));
+        assertEquals(170D, dataset.getY(0, 2));
+    }
+    
+    @Test
+    public void testAddDataMultiple() {
+        final String tag1 = "TESTGC1";
+        addChart(tag1, "Test GC1");
+        final String tag2 = "TESTGC2";
+        addChart(tag2, "Test GC2");
+        
+        List<IntervalTimeData<Double>> data1 = new ArrayList<IntervalTimeData<Double>>();
+        data1.add(new IntervalTimeData<Double>(1000L, 1500L, 100D));
+        data1.add(new IntervalTimeData<Double>(1500L, 2000L, 120D));
+        data1.add(new IntervalTimeData<Double>(2000L, 2500L, 170D));
+        
+        addData(tag1, data1);
+        
+        List<IntervalTimeData<Double>> data2 = new ArrayList<IntervalTimeData<Double>>();
+        data2.add(new IntervalTimeData<Double>(1200L, 1700L, 140D));
+        data2.add(new IntervalTimeData<Double>(1700L, 2200L, 130D));
+        data2.add(new IntervalTimeData<Double>(2200L, 2700L, 190D));
+        
+        addData(tag2, data2);
+        
+        JFreeChart chart1 = view.getChart(tag1);
+        IntervalXYDataset dataset1 = (IntervalXYDataset) chart1.getXYPlot().getDataset();
+        
+        assertEquals(1000L, dataset1.getStartX(0, 0));
+        assertEquals(1500L, dataset1.getEndX(0, 0));
+        assertEquals(100D, dataset1.getY(0, 0));
+        
+        assertEquals(1500L, dataset1.getStartX(0, 1));
+        assertEquals(2000L, dataset1.getEndX(0, 1));
+        assertEquals(120D, dataset1.getY(0, 1));
+        
+        assertEquals(2000L, dataset1.getStartX(0, 2));
+        assertEquals(2500L, dataset1.getEndX(0, 2));
+        assertEquals(170D, dataset1.getY(0, 2));
+        
+        JFreeChart chart2 = view.getChart(tag2);
+        IntervalXYDataset dataset2 = (IntervalXYDataset) chart2.getXYPlot().getDataset();
+        
+        assertEquals(1200L, dataset2.getStartX(0, 0));
+        assertEquals(1700L, dataset2.getEndX(0, 0));
+        assertEquals(140D, dataset2.getY(0, 0));
+        
+        assertEquals(1700L, dataset2.getStartX(0, 1));
+        assertEquals(2200L, dataset2.getEndX(0, 1));
+        assertEquals(130D, dataset2.getY(0, 1));
+        
+        assertEquals(2200L, dataset2.getStartX(0, 2));
+        assertEquals(2700L, dataset2.getEndX(0, 2));
+        assertEquals(190D, dataset2.getY(0, 2));
+    }
+
+    private void addData(final String tag,
+            List<IntervalTimeData<Double>> data) {
+        view.addData(tag, data);
+        
+        bot.waitUntil(new DefaultCondition() {
+            
+            @Override
+            public boolean test() throws Exception {
+                JFreeChart chart = view.getChart(tag);
+                return chart.getXYPlot().getDataset().getItemCount(0) == 3;
+            }
+            
+            @Override
+            public String getFailureMessage() {
+                return "Data not added";
+            }
+        });
+    }
+
+    @Test
+    public void testClearData() {
+        final String tag1 = "TESTGC1";
+        addChart(tag1, "Test GC1");
+        final String tag2 = "TESTGC2";
+        addChart(tag2, "Test GC2");
+        
+        List<IntervalTimeData<Double>> data1 = new ArrayList<IntervalTimeData<Double>>();
+        data1.add(new IntervalTimeData<Double>(1000L, 1500L, 100D));
+        data1.add(new IntervalTimeData<Double>(1500L, 2000L, 120D));
+        data1.add(new IntervalTimeData<Double>(2000L, 2500L, 170D));
+        
+        addData(tag1, data1);
+        
+        List<IntervalTimeData<Double>> data2 = new ArrayList<IntervalTimeData<Double>>();
+        data2.add(new IntervalTimeData<Double>(1200L, 1700L, 140D));
+        data2.add(new IntervalTimeData<Double>(1700L, 2200L, 130D));
+        data2.add(new IntervalTimeData<Double>(2200L, 2700L, 190D));
+        
+        addData(tag2, data2);
+        
+        // Remove data from the first chart
+        view.clearData(tag1);
+        
+        bot.waitUntil(new DefaultCondition() {
+            
+            @Override
+            public boolean test() throws Exception {
+                JFreeChart chart = view.getChart(tag1);
+                return chart.getXYPlot().getDataset().getItemCount(0) == 0;
+            }
+            
+            @Override
+            public String getFailureMessage() {
+                return "Data not removed";
+            }
+        });
+        
+        // Ensure other chart unchanged
+        assertEquals(3, view.getChart(tag2).getXYPlot().getDataset().getItemCount(0));
+    }
+
+}
--- a/eclipse/com.redhat.thermostat.eclipse.test/META-INF/MANIFEST.MF	Fri Oct 26 13:13:42 2012 +0200
+++ b/eclipse/com.redhat.thermostat.eclipse.test/META-INF/MANIFEST.MF	Fri Oct 26 15:32:56 2012 +0200
@@ -12,11 +12,17 @@
  com.redhat.thermostat.bundles.org.objenesis;resolution:=optional,
  com.redhat.thermostat.bundles.org.mockito.mockito-core;resolution:=optional
 Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Import-Package: com.redhat.thermostat.common,
+Import-Package: com.redhat.thermostat.client.core.views,
+ com.redhat.thermostat.client.osgi.service,
+ com.redhat.thermostat.client.ui,
+ com.redhat.thermostat.common,
  com.redhat.thermostat.common.dao,
+ com.redhat.thermostat.common.utils,
+ com.redhat.thermostat.eclipse,
+ com.redhat.thermostat.eclipse.chart.common,
  com.redhat.thermostat.eclipse.model,
- org.eclipse.core.resources,
- org.eclipse.ui.ide,
+ com.redhat.thermostat.eclipse.views,
  org.mockito,
  org.mockito.stubbing
-Export-Package: com.redhat.thermostat.eclipse.test.model
+Export-Package: com.redhat.thermostat.eclipse.test.model,
+ com.redhat.thermostat.eclipse.test.views
--- a/eclipse/com.redhat.thermostat.eclipse.test/pom.xml	Fri Oct 26 13:13:42 2012 +0200
+++ b/eclipse/com.redhat.thermostat.eclipse.test/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -16,8 +16,25 @@
 
   <dependencies>
     <dependency>
+      <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+      <artifactId>com.redhat.thermostat.eclipse</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <!-- using Web storage -->
+    <dependency>
       <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-common-core</artifactId>
+      <artifactId>thermostat-web-client</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-web-common</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <!-- DbService is in the launcher bundle -->
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-launcher</artifactId>
       <version>0.5.0-SNAPSHOT</version>
     </dependency>
     <dependency>
@@ -33,10 +50,9 @@
         <groupId>org.eclipse.tycho</groupId>
         <artifactId>tycho-surefire-plugin</artifactId>
         <version>${tycho-version}</version>
-        <!--
         <configuration>
           <useUIHarness>true</useUIHarness>
-          <useUIThread>false</useUIThread>
+          <useUIThread>true</useUIThread>
           <product>org.eclipse.platform.ide</product>
           <dependencies>
             <dependency>
@@ -44,9 +60,30 @@
               <artifactId>org.eclipse.sdk.feature.group</artifactId>
               <version>${sdk-version}</version>
             </dependency>
-          </dependencies>   
+          </dependencies>
+          <bundleStartLevel>
+            <bundle>
+              <id>com.redhat.thermostat.common.core</id>
+              <level>4</level>
+              <autoStart>true</autoStart>
+            </bundle>
+            <bundle>
+              <id>com.redhat.thermostat.web.common</id>
+              <level>4</level>
+              <autoStart>true</autoStart>
+            </bundle>
+            <bundle>
+              <id>com.redhat.thermostat.web.client</id>
+              <level>4</level>
+              <autoStart>true</autoStart>
+            </bundle>
+            <bundle>
+              <id>com.redhat.thermostat.launcher</id>
+              <level>4</level>
+              <autoStart>true</autoStart>
+            </bundle>
+          </bundleStartLevel>
         </configuration>
-        -->
       </plugin>
     </plugins>
   </build>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test/src/com/redhat/thermostat/eclipse/test/views/AbstractRefViewPartTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.eclipse.test.views;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.ISelectionService;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.junit.Before;
+
+import com.redhat.thermostat.common.dao.Ref;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.eclipse.ThermostatConstants;
+import com.redhat.thermostat.eclipse.chart.common.RefViewPart;
+import com.redhat.thermostat.eclipse.views.HostsVmsTreeViewPart;
+import com.redhat.thermostat.eclipse.views.SWTComponent;
+
+public abstract class AbstractRefViewPartTest<T extends Ref> {
+
+    protected Composite parent;
+    protected RefViewPart<T> view;
+    protected SWTComponent thermoView;
+    protected HostsVmsTreeViewPart hostVMView;
+    private ISelectionProvider provider;
+    protected OSGIUtils osgi;
+
+    public AbstractRefViewPartTest() {
+        super();
+    }
+
+    @Before
+    public void before() {
+        parent = spy(new Shell(Display.getCurrent()));
+        
+        view = spy(createViewPart());
+        hostVMView = mock(HostsVmsTreeViewPart.class);
+        osgi = mock(OSGIUtils.class);
+        OSGIUtils.setInstance(osgi);
+    
+        // Workbench mocks
+        IWorkbenchWindow window = mock(IWorkbenchWindow.class);
+        IWorkbenchPage page = mock(IWorkbenchPage.class);
+        ISelectionService service = mock(ISelectionService.class);
+        
+        when(page.findView(ThermostatConstants.VIEW_ID_HOST_VM)).thenReturn(hostVMView);
+        when(window.getSelectionService()).thenReturn(service);
+        when(window.getActivePage()).thenReturn(page);
+        when(view.getWorkbenchWindow()).thenReturn(window);
+        
+        // Controller mock
+        mockController();
+        
+        // Selection mocks
+        IWorkbenchPartSite site = mock(IWorkbenchPartSite.class);
+        provider = mock(ISelectionProvider.class);
+    
+        when(site.getSelectionProvider()).thenReturn(provider);
+        when(hostVMView.getSite()).thenReturn(site);
+    }
+
+    protected abstract void mockController();
+
+    protected abstract RefViewPart<T> createViewPart();
+
+    protected IStructuredSelection mockSelection(Ref ref) {
+        IStructuredSelection selection = mock(IStructuredSelection.class);;
+        when(provider.getSelection()).thenReturn(selection);
+        when(selection.getFirstElement()).thenReturn(ref);
+        
+        return selection;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test/src/com/redhat/thermostat/eclipse/test/views/HostCpuViewPartTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.eclipse.test.views;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.widgets.Composite;
+import org.junit.Test;
+
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.core.views.HostCpuViewProvider;
+import com.redhat.thermostat.client.ui.HostCpuController;
+import com.redhat.thermostat.common.dao.CpuStatDAO;
+import com.redhat.thermostat.common.dao.HostInfoDAO;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.eclipse.chart.common.HostCpuViewPart;
+import com.redhat.thermostat.eclipse.chart.common.RefViewPart;
+import com.redhat.thermostat.eclipse.chart.common.SWTHostCpuView;
+
+public class HostCpuViewPartTest extends AbstractRefViewPartTest<HostRef> {
+
+    @Test
+    public void testSetFocus() throws Exception {
+        view.createPartControl(parent);
+        view.setFocus();
+
+        verify(parent).setFocus();
+    }
+
+    @Test
+    public void testNoSelection() throws Exception {
+        view.createPartControl(parent);
+        verify(view).createNoSelectionLabel();
+    }
+
+    @Test
+    public void testSelectionBefore() throws Exception {
+        HostRef hostRef = new HostRef("TEST", "Test");
+        mockSelection(hostRef);
+        view.createPartControl(parent);
+
+        verify(view, never()).createNoSelectionLabel();
+
+        verify(thermoView).createControl(any(Composite.class));
+    }
+
+    @Test
+    public void testSelectionAfter() throws Exception {
+        view.createPartControl(parent);
+
+        HostRef hostRef = new HostRef("TEST", "Test");
+        IStructuredSelection selection = mockSelection(hostRef);
+        view.selectionChanged(hostVMView, selection);
+
+        verify(thermoView).createControl(any(Composite.class));
+    }
+
+    @Test
+    public void testSelectionVmRef() throws Exception {
+        view.createPartControl(parent);
+
+        HostRef hostRef = new HostRef("TEST", "Test");
+        VmRef vmRef = new VmRef(hostRef, 0, "Test");
+        IStructuredSelection selection = mockSelection(vmRef);
+        view.selectionChanged(hostVMView, selection);
+
+        verify(thermoView).createControl(any(Composite.class));
+    }
+
+    @Override
+    protected RefViewPart<HostRef> createViewPart() {
+        return new HostCpuViewPart();
+    }
+
+    @Override
+    protected void mockController() {
+        HostCpuController controller = mock(HostCpuController.class);
+        thermoView = mock(SWTHostCpuView.class);
+
+        HostInfoDAO hostInfoDao = mock(HostInfoDAO.class);
+        CpuStatDAO cpuStatDao = mock(CpuStatDAO.class);
+        HostCpuViewProvider viewProvider = mock(HostCpuViewProvider.class);
+        when(osgi.getService(HostInfoDAO.class)).thenReturn(hostInfoDao);
+        when(osgi.getService(CpuStatDAO.class)).thenReturn(cpuStatDao);
+        when(osgi.getService(HostCpuViewProvider.class)).thenReturn(
+                viewProvider);
+
+        doReturn(controller).when(((HostCpuViewPart) view)).createController(
+                same(hostInfoDao), same(cpuStatDao), any(HostRef.class),
+                same(viewProvider));
+        when(controller.getView()).thenReturn((BasicView) thermoView);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test/src/com/redhat/thermostat/eclipse/test/views/HostMemoryViewPartTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,97 @@
+/*
+ * 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.eclipse.test.views;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.widgets.Composite;
+import org.junit.Test;
+
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.core.views.HostMemoryViewProvider;
+import com.redhat.thermostat.client.ui.HostMemoryController;
+import com.redhat.thermostat.common.dao.HostInfoDAO;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.MemoryStatDAO;
+import com.redhat.thermostat.eclipse.chart.common.HostMemoryViewPart;
+import com.redhat.thermostat.eclipse.chart.common.RefViewPart;
+import com.redhat.thermostat.eclipse.chart.common.SWTHostMemoryView;
+
+public class HostMemoryViewPartTest extends AbstractRefViewPartTest<HostRef> {
+
+    @Test
+    public void testSelectionAfter() throws Exception {
+        view.createPartControl(parent);
+
+        HostRef hostRef = new HostRef("TEST", "Test");
+        IStructuredSelection selection = mockSelection(hostRef);
+        view.selectionChanged(hostVMView, selection);
+
+        verify(thermoView).createControl(any(Composite.class));
+    }
+
+    @Override
+    protected void mockController() {
+        HostMemoryController controller = mock(HostMemoryController.class);
+        thermoView = mock(SWTHostMemoryView.class);
+
+        HostInfoDAO hostInfoDao = mock(HostInfoDAO.class);
+        MemoryStatDAO memStatDao = mock(MemoryStatDAO.class);
+        HostMemoryViewProvider viewProvider = mock(HostMemoryViewProvider.class);
+        when(osgi.getService(HostInfoDAO.class)).thenReturn(hostInfoDao);
+        when(osgi.getService(MemoryStatDAO.class)).thenReturn(memStatDao);
+        when(osgi.getService(HostMemoryViewProvider.class)).thenReturn(
+                viewProvider);
+
+        doReturn(controller).when(((HostMemoryViewPart) view))
+                .createController(same(hostInfoDao), same(memStatDao),
+                        any(HostRef.class), same(viewProvider));
+        when(controller.getView()).thenReturn((BasicView) thermoView);
+    }
+
+    @Override
+    protected RefViewPart<HostRef> createViewPart() {
+        return new HostMemoryViewPart();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test/src/com/redhat/thermostat/eclipse/test/views/ThermostatPerspectiveTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.eclipse.test.views;
+
+import static org.mockito.Matchers.anyFloat;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.eclipse.ui.IFolderLayout;
+import org.eclipse.ui.IPageLayout;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.eclipse.ThermostatConstants;
+import com.redhat.thermostat.eclipse.views.ThermostatPerspectiveFactory;
+
+public class ThermostatPerspectiveTest {
+    
+    private IFolderLayout leftFolder;
+    private IFolderLayout rightFolder;
+    private IPageLayout layout;
+
+    @Before
+    public void createLayout() {
+        ThermostatPerspectiveFactory factory = new ThermostatPerspectiveFactory();
+        layout = mock(IPageLayout.class);
+        leftFolder = mock(IFolderLayout.class);
+        rightFolder = mock(IFolderLayout.class);
+        when(layout.createFolder(eq(ThermostatPerspectiveFactory.FOLDER_LEFT), anyInt(), anyFloat(), anyString())).thenReturn(leftFolder);
+        when(layout.createFolder(eq(ThermostatPerspectiveFactory.FOLDER_RIGHT), anyInt(), anyFloat(), anyString())).thenReturn(rightFolder);
+        factory.createInitialLayout(layout);
+    }
+
+    @Test
+    public void testHostVMViewAdded() {
+        verifyViewAdded(ThermostatConstants.VIEW_ID_HOST_VM, leftFolder);
+    }
+    
+    @Test
+    public void testHostVMShortcutAdded() {
+        verifyShortcutAdded(ThermostatConstants.VIEW_ID_HOST_VM);
+    }
+    
+    @Test
+    public void testHostOverviewViewAdded() {
+        verifyViewAdded(ThermostatConstants.VIEW_ID_HOST_OVERVIEW, rightFolder);
+    }
+    
+    @Test
+    public void testHostOverviewShortcutAdded() {
+        verifyShortcutAdded(ThermostatConstants.VIEW_ID_HOST_OVERVIEW);
+    }
+    
+    @Test
+    public void testHostCPUViewAdded() {
+        verifyViewAdded(ThermostatConstants.VIEW_ID_HOST_CPU, rightFolder);
+    }
+    
+    @Test
+    public void testHostCPUShortcutAdded() {
+        verifyShortcutAdded(ThermostatConstants.VIEW_ID_HOST_CPU);
+    }
+    
+    @Test
+    public void testHostMemoryViewAdded() {
+        verifyViewAdded(ThermostatConstants.VIEW_ID_HOST_MEMORY, rightFolder);
+    }
+    
+    @Test
+    public void testHostMemoryShortcutAdded() {
+        verifyShortcutAdded(ThermostatConstants.VIEW_ID_HOST_MEMORY);
+    }
+    
+    @Test
+    public void testVMCPUViewAdded() {
+        verifyViewAdded(ThermostatConstants.VIEW_ID_VM_CPU, rightFolder);
+    }
+    
+    @Test
+    public void testVMCPUShortcutAdded() {
+        verifyShortcutAdded(ThermostatConstants.VIEW_ID_VM_CPU);
+    }
+    
+    @Test
+    public void testVMGCViewAdded() {
+        verifyViewAdded(ThermostatConstants.VIEW_ID_VM_GC, rightFolder);
+    }
+    
+    @Test
+    public void testVMGCShortcutAdded() {
+        verifyShortcutAdded(ThermostatConstants.VIEW_ID_VM_GC);
+    }
+    
+    private void verifyViewAdded(String viewID, IFolderLayout folder) {
+        verify(folder).addView(viewID);
+    }
+    
+    private void verifyShortcutAdded(String viewID) {
+        verify(layout).addShowViewShortcut(viewID);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test/src/com/redhat/thermostat/eclipse/test/views/ViewVisibilityWatcherTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,187 @@
+/*
+ * 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.eclipse.test.views;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.core.views.BasicView.Action;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ActionNotifier;
+import com.redhat.thermostat.eclipse.chart.common.ViewVisibilityWatcher;
+
+public class ViewVisibilityWatcherTest {
+    private static final Long TIME_OUT_MILLIS = 5000L;
+    private static final String VIEW_ID = IPageLayout.ID_PROBLEM_VIEW;
+    private IViewPart view;
+    private Shell shell;
+    private CountDownLatch latch;
+
+    @Before
+    public void beforeTest() throws Exception {
+        shell = new Shell(Display.getCurrent());
+    }
+
+    @After
+    public void afterTest() throws Exception {
+        shell = null;
+    }
+
+    @Test
+    public void testVisibleBeforeAttach() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final Action[] action = new Action[1];
+
+        ActionNotifier<Action> notifier = new ActionNotifier<>(this);
+        notifier.addActionListener(new ActionListener<BasicView.Action>() {
+
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                action[0] = actionEvent.getActionId();
+                latch.countDown();
+            }
+        });
+
+        ViewVisibilityWatcher watcher = new ViewVisibilityWatcher(notifier);
+
+        showView();
+
+        // Attach
+        watcher.watch(shell, VIEW_ID);
+
+        waitForAction(latch);
+
+        assertEquals(Action.VISIBLE, action[0]);
+    }
+
+    @Test
+    public void testVisibleAfterAttach() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final Action[] action = new Action[1];
+
+        ActionNotifier<Action> notifier = new ActionNotifier<>(this);
+        notifier.addActionListener(new ActionListener<BasicView.Action>() {
+
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                action[0] = actionEvent.getActionId();
+                latch.countDown();
+            }
+        });
+
+        ViewVisibilityWatcher watcher = new ViewVisibilityWatcher(notifier);
+
+        // Attach
+        watcher.watch(shell, VIEW_ID);
+
+        showView();
+
+        waitForAction(latch);
+
+        assertEquals(Action.VISIBLE, action[0]);
+    }
+
+    @Test
+    public void testVisibleBeforeAttachHiddenAfter() throws Exception {
+        latch = new CountDownLatch(1);
+
+        final Action[] action = new Action[1];
+
+        ActionNotifier<Action> notifier = new ActionNotifier<>(this);
+        notifier.addActionListener(new ActionListener<BasicView.Action>() {
+
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                action[0] = actionEvent.getActionId();
+                latch.countDown();
+            }
+        });
+
+        ViewVisibilityWatcher watcher = new ViewVisibilityWatcher(notifier);
+
+        showView();
+
+        // Attach
+        watcher.watch(shell, VIEW_ID);
+
+        waitForAction(latch);
+
+        assertEquals(Action.VISIBLE, action[0]);
+
+        // Hide view
+        latch = new CountDownLatch(1);
+
+        hideView();
+
+        waitForAction(latch);
+
+        assertEquals(Action.HIDDEN, action[0]);
+    }
+
+    private void waitForAction(final CountDownLatch latch)
+            throws InterruptedException {
+        if (!latch.await(TIME_OUT_MILLIS, TimeUnit.MILLISECONDS)) {
+            fail("Timeout while waiting for action");
+        }
+    }
+
+    private void showView() throws PartInitException {
+        view = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
+                .getActivePage().showView(VIEW_ID);
+    }
+
+    private void hideView() {
+        PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
+                .hideView(view);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test/src/com/redhat/thermostat/eclipse/test/views/VmCpuViewPartTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,106 @@
+/*
+ * 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.eclipse.test.views;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.widgets.Composite;
+import org.junit.Test;
+
+import com.redhat.thermostat.client.core.views.VmCpuViewProvider;
+import com.redhat.thermostat.client.ui.VmCpuController;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.VmCpuStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.eclipse.chart.common.RefViewPart;
+import com.redhat.thermostat.eclipse.chart.common.SWTVmCpuView;
+import com.redhat.thermostat.eclipse.chart.common.VmCpuViewPart;
+
+public class VmCpuViewPartTest extends AbstractRefViewPartTest<VmRef> {
+
+    @Test
+    public void testSelectionHostRef() throws Exception {
+        view.createPartControl(parent);
+
+        HostRef hostRef = new HostRef("TEST", "Test");
+        IStructuredSelection selection = mockSelection(hostRef);
+        view.selectionChanged(hostVMView, selection);
+
+        // Ensure not created
+        verify(thermoView, never()).createControl(any(Composite.class));
+    }
+
+    @Test
+    public void testSelectionAfter() throws Exception {
+        view.createPartControl(parent);
+
+        HostRef hostRef = new HostRef("TEST", "Test");
+        VmRef vmRef = new VmRef(hostRef, 0, "Test");
+        IStructuredSelection selection = mockSelection(vmRef);
+        view.selectionChanged(hostVMView, selection);
+
+        verify(thermoView).createControl(any(Composite.class));
+    }
+
+    @Override
+    protected void mockController() {
+        VmCpuController controller = mock(VmCpuController.class);
+        thermoView = mock(SWTVmCpuView.class);
+
+        VmCpuStatDAO cpuStatDao = mock(VmCpuStatDAO.class);
+        VmCpuViewProvider viewProvider = mock(VmCpuViewProvider.class);
+        when(osgi.getService(VmCpuStatDAO.class)).thenReturn(cpuStatDao);
+        when(osgi.getService(VmCpuViewProvider.class)).thenReturn(viewProvider);
+
+        doReturn(controller).when(((VmCpuViewPart) view)).createController(
+                same(cpuStatDao), any(VmRef.class), same(viewProvider));
+        when(controller.getView()).thenReturn(thermoView);
+    }
+
+    @Override
+    protected RefViewPart<VmRef> createViewPart() {
+        return new VmCpuViewPart();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse.test/src/com/redhat/thermostat/eclipse/test/views/VmGcViewPartTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,97 @@
+/*
+ * 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.eclipse.test.views;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.widgets.Composite;
+import org.junit.Test;
+
+import com.redhat.thermostat.client.core.views.VmGcViewProvider;
+import com.redhat.thermostat.client.ui.VmGcController;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.VmGcStatDAO;
+import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.eclipse.chart.common.RefViewPart;
+import com.redhat.thermostat.eclipse.chart.common.SWTVmGcView;
+import com.redhat.thermostat.eclipse.chart.common.VmGcViewPart;
+
+public class VmGcViewPartTest extends AbstractRefViewPartTest<VmRef> {
+
+    @Test
+    public void testSelectionAfter() throws Exception {
+        view.createPartControl(parent);
+
+        HostRef hostRef = new HostRef("TEST", "Test");
+        VmRef vmRef = new VmRef(hostRef, 0, "Test");
+        IStructuredSelection selection = mockSelection(vmRef);
+        view.selectionChanged(hostVMView, selection);
+
+        verify(thermoView).createControl(any(Composite.class));
+    }
+
+    @Override
+    protected void mockController() {
+        VmGcController controller = mock(VmGcController.class);
+        thermoView = mock(SWTVmGcView.class);
+
+        VmMemoryStatDAO memStatDao = mock(VmMemoryStatDAO.class);
+        VmGcStatDAO gcStatDao = mock(VmGcStatDAO.class);
+        VmGcViewProvider viewProvider = mock(VmGcViewProvider.class);
+        when(osgi.getService(VmMemoryStatDAO.class)).thenReturn(memStatDao);
+        when(osgi.getService(VmGcStatDAO.class)).thenReturn(gcStatDao);
+        when(osgi.getService(VmGcViewProvider.class)).thenReturn(viewProvider);
+
+        doReturn(controller).when(((VmGcViewPart) view)).createController(
+                same(memStatDao), same(gcStatDao), any(VmRef.class),
+                same(viewProvider));
+        when(controller.getView()).thenReturn(thermoView);
+    }
+
+    @Override
+    protected RefViewPart<VmRef> createViewPart() {
+        return new VmGcViewPart();
+    }
+
+}
--- a/eclipse/com.redhat.thermostat.eclipse/META-INF/MANIFEST.MF	Fri Oct 26 13:13:42 2012 +0200
+++ b/eclipse/com.redhat.thermostat.eclipse/META-INF/MANIFEST.MF	Fri Oct 26 15:32:56 2012 +0200
@@ -10,12 +10,17 @@
 Require-Bundle: org.eclipse.core.runtime,
  org.eclipse.ui
 Import-Package: com.mongodb,
+ com.redhat.thermostat.client.core.views,
  com.redhat.thermostat.common,
  com.redhat.thermostat.common.appctx,
  com.redhat.thermostat.common.config,
  com.redhat.thermostat.common.dao,
  com.redhat.thermostat.common.model,
- com.redhat.thermostat.common.storage
-Export-Package: com.redhat.thermostat.eclipse;x-friends:=com.redhat.thermostat.eclipse.test,
- com.redhat.thermostat.eclipse.model;x-friends:=com.redhat.thermostat.eclipse.test,
- com.redhat.thermostat.eclipse.views;x-friends:=com.redhat.thermostat.eclipse.test
+ com.redhat.thermostat.common.storage,
+ com.redhat.thermostat.common.utils,
+ com.redhat.thermostat.launcher,
+ com.redhat.thermostat.web.client,
+ com.redhat.thermostat.web.common
+Export-Package: com.redhat.thermostat.eclipse;x-friends:="com.redhat.thermostat.eclipse.test,com.redhat.thermostat.eclipse.chart.common,com.redhat.thermostat.eclipse.test.ui",
+ com.redhat.thermostat.eclipse.model;x-friends:="com.redhat.thermostat.eclipse.test,com.redhat.thermostat.eclipse.chart.common,com.redhat.thermostat.eclipse.test.ui",
+ com.redhat.thermostat.eclipse.views;x-friends:="com.redhat.thermostat.eclipse.test,com.redhat.thermostat.eclipse.chart.common,com.redhat.thermostat.eclipse.test.ui"
--- a/eclipse/com.redhat.thermostat.eclipse/plugin.xml	Fri Oct 26 13:13:42 2012 +0200
+++ b/eclipse/com.redhat.thermostat.eclipse/plugin.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -59,4 +59,12 @@
             restorable="true">
       </view>
    </extension>
+   <extension
+         point="org.eclipse.ui.perspectives">
+      <perspective
+            class="com.redhat.thermostat.eclipse.views.ThermostatPerspectiveFactory"
+            id="com.redhat.thermostat.eclipse.perspective"
+            name="Thermostat">
+      </perspective>
+   </extension>
 </plugin>
--- a/eclipse/com.redhat.thermostat.eclipse/pom.xml	Fri Oct 26 13:13:42 2012 +0200
+++ b/eclipse/com.redhat.thermostat.eclipse/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -17,7 +17,24 @@
   <dependencies>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-common-core</artifactId>
+      <artifactId>thermostat-client-core</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <!-- using Web storage -->
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-web-client</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-web-common</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <!-- DbService is in the launcher bundle -->
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-launcher</artifactId>
       <version>0.5.0-SNAPSHOT</version>
     </dependency>
   </dependencies>
--- a/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/Activator.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/Activator.java	Fri Oct 26 15:32:56 2012 +0200
@@ -43,17 +43,18 @@
 import org.eclipse.ui.plugin.AbstractUIPlugin;
 import org.osgi.framework.BundleContext;
 
+import com.redhat.thermostat.common.ThreadPoolTimerFactory;
+import com.redhat.thermostat.common.TimerFactory;
 import com.redhat.thermostat.common.appctx.ApplicationContext;
-import com.redhat.thermostat.common.storage.Connection;
+import com.redhat.thermostat.common.storage.ConnectionException;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+import com.redhat.thermostat.launcher.DbService;
 
 /**
  * The activator class controls the plug-in life cycle
  */
 public class Activator extends AbstractUIPlugin {
 
-    // Storage connection status
-    private volatile boolean connected = false;
-
     // The plug-in ID
     public static final String PLUGIN_ID = "com.redhat.thermostat.eclipse"; //$NON-NLS-1$
 
@@ -66,14 +67,6 @@
     public Activator() {
     }
 
-    public boolean isConnected() {
-        return connected;
-    }
-
-    public void setConnected(boolean connected) {
-        this.connected = connected;
-    }
-
     /*
      * (non-Javadoc)
      * 
@@ -84,6 +77,10 @@
     public void start(BundleContext context) throws Exception {
         super.start(context);
         plugin = this;
+        
+        // Register a TimerFactory
+        TimerFactory timerFactory = new ThreadPoolTimerFactory(1);
+        ApplicationContext.getInstance().setTimerFactory(timerFactory);
     }
 
     /*
@@ -94,11 +91,13 @@
      * )
      */
     public void stop(BundleContext context) throws Exception {
-        if (isConnected()) {
-            Connection connection = ApplicationContext.getInstance()
-                    .getDAOFactory().getConnection();
-            connection.disconnect();
+        DbService dbService = OSGIUtils.getInstance().getService(DbService.class);
+        try {
+            dbService.disconnect();
+        } catch (ConnectionException e) {
+            e.printStackTrace();
         }
+        dbService.getServiceRegistration().unregister();
         plugin = null;
         super.stop(context);
     }
@@ -151,5 +150,10 @@
     public static ImageDescriptor getImageDescriptor(String path) {
         return imageDescriptorFromPlugin(PLUGIN_ID, path);
     }
+    
+    public boolean isDbConnected() {
+        DbService dbService = OSGIUtils.getInstance().getServiceAllowNull(DbService.class);
+        return dbService != null;
+    }
 
 }
--- a/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/ConnectionConfiguration.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/ConnectionConfiguration.java	Fri Oct 26 15:32:56 2012 +0200
@@ -41,10 +41,21 @@
 public class ConnectionConfiguration implements StartupConfiguration {
 
     private String dbUrl;
+    private String username;
+    private String password;
+    
+    public ConnectionConfiguration(String username, String password, String dbUrl) {
+        this.dbUrl = dbUrl;
+        this.username = username;
+        this.password = password;
+    }
 
-    // FIXME: Adapt to more dynamic requirements
-    public ConnectionConfiguration(String dbUrl) {
-        this.dbUrl = dbUrl;
+    public String getUsername() {
+        return username;
+    }
+
+    public String getPassword() {
+        return password;
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/ThermostatConstants.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,52 @@
+/*
+ * 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.eclipse;
+
+public interface ThermostatConstants {
+    
+    public static final String PERSPECTIVE_ID = "com.redhat.thermostat.eclipse.perspective";
+    
+    public static final String VIEW_ID_HOST_VM = "com.redhat.thermostat.eclipse.vmtree";
+    public static final String VIEW_ID_HOST_OVERVIEW = "com.redhat.thermostat.eclipse.mainContainer";
+    public static final String VIEW_ID_HOST_CPU = "com.redhat.thermostat.eclipse.chart.hostCpuView";
+    public static final String VIEW_ID_HOST_MEMORY = "com.redhat.thermostat.eclipse.chart.hostMemoryView";
+    public static final String VIEW_ID_VM_CPU = "com.redhat.thermostat.eclipse.chart.vmCpuView";
+    public static final String VIEW_ID_VM_GC = "com.redhat.thermostat.eclipse.chart.vmGcView";
+    
+    public static final String TEST_TAG = "com.redhat.thermostat.eclipse.test.swtTag";
+
+}
--- a/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/controllers/ConnectionJobListener.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/controllers/ConnectionJobListener.java	Fri Oct 26 15:32:56 2012 +0200
@@ -60,7 +60,7 @@
         if (result.isOK()) {
             connectAction.setImageDescriptor(Activator
                     .getImageDescriptor("icons/online.png"));
-            connectAction.setEnabled(!Activator.getDefault().isConnected());
+            connectAction.setEnabled(!Activator.getDefault().isDbConnected());
             connectAction.setToolTipText("Online");
             view.showHostVmsPage();
         }
--- a/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/jobs/ConnectDbJob.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/jobs/ConnectDbJob.java	Fri Oct 26 15:32:56 2012 +0200
@@ -40,22 +40,14 @@
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.jobs.Job;
+import org.osgi.framework.BundleContext;
 
-import com.redhat.thermostat.common.ThreadPoolTimerFactory;
-import com.redhat.thermostat.common.TimerFactory;
-import com.redhat.thermostat.common.appctx.ApplicationContext;
-import com.redhat.thermostat.common.config.InvalidConfigurationException;
-import com.redhat.thermostat.common.dao.DAOFactory;
-import com.redhat.thermostat.common.dao.MongoDAOFactory;
-import com.redhat.thermostat.common.storage.Connection;
-import com.redhat.thermostat.common.storage.Connection.ConnectionListener;
-import com.redhat.thermostat.common.storage.Connection.ConnectionStatus;
 import com.redhat.thermostat.common.storage.ConnectionException;
-import com.redhat.thermostat.common.storage.MongoStorageProvider;
-import com.redhat.thermostat.common.storage.StorageProvider;
 import com.redhat.thermostat.eclipse.Activator;
 import com.redhat.thermostat.eclipse.ConnectionConfiguration;
 import com.redhat.thermostat.eclipse.LoggerFacility;
+import com.redhat.thermostat.launcher.DbService;
+import com.redhat.thermostat.launcher.DbServiceFactory;
 
 public class ConnectDbJob extends Job {
 
@@ -74,7 +66,7 @@
         try {
             connectToBackEnd();
             return Status.OK_STATUS;
-        } catch (InvalidConfigurationException | ConnectionException e) {
+        } catch (ConnectionException e) {
             LoggerFacility.getInstance().log(IStatus.ERROR,
                     "Could not connect to DB", e);
             return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Could not connect to DB", e);
@@ -82,46 +74,16 @@
     }
     
     /*
-     * Establish a Mongo DB connection.
+     * Establish a DB connection.
      */
-    private void connectToBackEnd() throws InvalidConfigurationException, ConnectionException {
-        StorageProvider connProv = new MongoStorageProvider(configuration);
-        DAOFactory daoFactory = new MongoDAOFactory(connProv);
-        ApplicationContext.getInstance().setDAOFactory(daoFactory);
-        TimerFactory timerFactory = new ThreadPoolTimerFactory(1);
-        ApplicationContext.getInstance().setTimerFactory(timerFactory);
-
-        Connection connection = daoFactory.getConnection();
-        ConnectionListener connectionListener = new ConnectionListener() {
-            @Override
-            public void changed(ConnectionStatus newStatus) {
-                switch (newStatus) {
-                case DISCONNECTED:
-                    LoggerFacility.getInstance().log(IStatus.WARNING,
-                            "Unexpected disconnect event.");
-                    break;
-                case CONNECTING:
-                    LoggerFacility.getInstance().log(IStatus.INFO,
-                            "Connecting to storage.");
-                    break;
-                case CONNECTED:
-                    LoggerFacility.getInstance().log(IStatus.INFO,
-                            "Connected to storage.");
-                    Activator.getDefault().setConnected(true);
-                    break;
-                case FAILED_TO_CONNECT:
-                    LoggerFacility.getInstance().log(IStatus.WARNING,
-                            "Could not connect to storage.");
-                default:
-                    LoggerFacility.getInstance().log(IStatus.WARNING,
-                            "Unfamiliar ConnectionStatus value");
-                }
-            }
-        };
-        connection.addListener(connectionListener);
-        LoggerFacility.getInstance().log(IStatus.INFO,
-                "Connecting to storage...");
-        connection.connect();
+    private void connectToBackEnd() throws ConnectionException {
+        DbServiceFactory dbServiceFactory = new DbServiceFactory();
+        DbService dbService = dbServiceFactory.createDbService(configuration.getUsername(),
+                configuration.getPassword(), configuration.getDBConnectionString());
+        dbService.connect();
+        // register service in order to indicate that we are connected
+        BundleContext ctxt = Activator.getDefault().getBundle().getBundleContext();
+        ctxt.registerService(DbService.class, dbService, null);
     }
 
 }
--- a/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/views/HostOverviewViewPart.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/views/HostOverviewViewPart.java	Fri Oct 26 15:32:56 2012 +0200
@@ -54,13 +54,12 @@
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.TableColumn;
 import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.IViewPart;
 import org.eclipse.ui.IWorkbenchPart;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.part.PageBook;
 import org.eclipse.ui.part.ViewPart;
 
-import com.redhat.thermostat.common.appctx.ApplicationContext;
-import com.redhat.thermostat.common.dao.DAOFactory;
 import com.redhat.thermostat.common.dao.HostInfoDAO;
 import com.redhat.thermostat.common.dao.HostRef;
 import com.redhat.thermostat.common.dao.NetworkInterfaceInfoDAO;
@@ -68,7 +67,9 @@
 import com.redhat.thermostat.common.dao.VmRef;
 import com.redhat.thermostat.common.model.HostInfo;
 import com.redhat.thermostat.common.model.NetworkInterfaceInfo;
+import com.redhat.thermostat.common.utils.OSGIUtils;
 import com.redhat.thermostat.eclipse.Activator;
+import com.redhat.thermostat.eclipse.ThermostatConstants;
 
 public class HostOverviewViewPart extends ViewPart {
 
@@ -103,7 +104,7 @@
                     && !selection.equals(oldSelection)) {
                 oldSelection = selection;
                 Ref ref = getRefFromSelection(selection);
-                if (Activator.getDefault().isConnected()) {
+                if (Activator.getDefault().isDbConnected()) {
                     if (ref != null) {
                         updateText(ref);
                         if (ref instanceof HostRef) {
@@ -251,23 +252,28 @@
 
         // Listen for VMtree changes
         getSite().getWorkbenchWindow().getSelectionService()
-                .addSelectionListener(listener);
-        if (Activator.getDefault().isConnected()) {
-            ISelection selection = getSite().getWorkbenchWindow()
-                    .getSelectionService().getSelection();
-            Ref ref = getRefFromSelection(selection);
-            if (ref != null) {
-                updateText(ref);
-                if (ref instanceof HostRef) {
-                    showPage(mainScrollPage);
-                } else {
-                    showPage(vmPage);
-                }
-            } else {
-                // FIXME: probably want to show something else, e.g. select x in
-                // VM tree
-                showPage(notConnectedPage);
-            }
+        .addSelectionListener(listener);
+        if (Activator.getDefault().isDbConnected()) {
+        	// Explicitly get the selected element from the VmsTreeViewPart
+        	IViewPart part = getSite().getWorkbenchWindow().getActivePage().findView(ThermostatConstants.VIEW_ID_HOST_VM);
+        	if (part != null && part instanceof HostsVmsTreeViewPart) {
+        		ISelection selection = part.getSite().getSelectionProvider().getSelection();
+        		Ref ref = getRefFromSelection(selection);
+        		if (ref != null) {
+        			updateText(ref);
+        			if (ref instanceof HostRef) {
+        				showPage(mainScrollPage);
+        			} else {
+        				showPage(vmPage);
+        			}
+        		} else {
+        			// FIXME: probably want to show something else, e.g. select x in
+        			// VM tree
+        			showPage(notConnectedPage);
+        		}
+        	} else {
+        		showPage(notConnectedPage);
+        	}
         } else {
             showPage(notConnectedPage);
         }
@@ -287,11 +293,11 @@
     }
 
     private void updateText(final HostRef hostRef) {
-        DAOFactory df = ApplicationContext.getInstance().getDAOFactory();
-        HostInfoDAO hostInfoDAO = df.getHostInfoDAO();
+        HostInfoDAO hostInfoDAO = OSGIUtils.getInstance().getService(
+                HostInfoDAO.class);
         final HostInfo hostInfo = hostInfoDAO.getHostInfo(hostRef);
-        final NetworkInterfaceInfoDAO networkInfoDAO = df
-                .getNetworkInterfaceInfoDAO();
+        final NetworkInterfaceInfoDAO networkInfoDAO = OSGIUtils.getInstance()
+                .getService(NetworkInterfaceInfoDAO.class);
         PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
             @Override
             public void run() {
--- a/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/views/HostsVmsTreeViewPart.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/views/HostsVmsTreeViewPart.java	Fri Oct 26 15:32:56 2012 +0200
@@ -53,9 +53,9 @@
 
 import com.redhat.thermostat.common.DefaultHostsVMsLoader;
 import com.redhat.thermostat.common.HostsVMsLoader;
-import com.redhat.thermostat.common.appctx.ApplicationContext;
 import com.redhat.thermostat.common.dao.HostInfoDAO;
 import com.redhat.thermostat.common.dao.VmInfoDAO;
+import com.redhat.thermostat.common.utils.OSGIUtils;
 import com.redhat.thermostat.eclipse.Activator;
 import com.redhat.thermostat.eclipse.ConnectionConfiguration;
 import com.redhat.thermostat.eclipse.controllers.ConnectDBAction;
@@ -81,7 +81,8 @@
     private PageBook pageBook;
 
     public HostsVmsTreeViewPart() {
-        ConnectionConfiguration configuration = new ConnectionConfiguration("mongodb://127.0.0.1:27518");
+        // FIXME: Get these values from preferences
+        ConnectionConfiguration configuration = new ConnectionConfiguration("dummyUser", "dummyPassword", "mongodb://127.0.0.1:27518");
         Job connectJob = new ConnectDbJob(
                 "Connecting to Thermostat storage...", configuration);
         connectJob.setSystem(true);
@@ -101,10 +102,10 @@
     }
 
     public void showHostVmsPage() {
-        HostInfoDAO hostDAO = ApplicationContext.getInstance().getDAOFactory()
-                .getHostInfoDAO();
-        VmInfoDAO vmsDAO = ApplicationContext.getInstance().getDAOFactory()
-                .getVmInfoDAO();
+        HostInfoDAO hostDAO = OSGIUtils.getInstance().getService(
+                HostInfoDAO.class);
+        VmInfoDAO vmsDAO = OSGIUtils.getInstance().getService(
+                VmInfoDAO.class);
         final HostsVMsLoader loader = new DefaultHostsVMsLoader(hostDAO,
                 vmsDAO, false);
 
@@ -152,8 +153,7 @@
             }
         });
         // Show appropriate page
-        boolean connected = Activator.getDefault().isConnected();
-        if (connected) {
+        if (Activator.getDefault().isDbConnected()) {
             showHostVmsPage();
         } else {
             showConnectionPage();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/views/SWTComponent.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.eclipse.views;
+
+import org.eclipse.swt.widgets.Composite;
+
+import com.redhat.thermostat.client.core.views.UIComponent;
+
+public interface SWTComponent extends UIComponent {
+    
+    public void createControl(Composite parent);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/com.redhat.thermostat.eclipse/src/com/redhat/thermostat/eclipse/views/ThermostatPerspectiveFactory.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.eclipse.views;
+
+import org.eclipse.ui.IFolderLayout;
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IPerspectiveFactory;
+
+import com.redhat.thermostat.eclipse.ThermostatConstants;
+
+public class ThermostatPerspectiveFactory implements IPerspectiveFactory {
+    
+    public static final String FOLDER_LEFT = "left";
+    public static final String FOLDER_RIGHT = "right";
+
+    @Override
+    public void createInitialLayout(IPageLayout layout) {
+        defineActions(layout);
+        defineLayout(layout);
+    }
+
+    private void defineLayout(IPageLayout layout) {
+        IFolderLayout left = layout.createFolder(FOLDER_LEFT, IPageLayout.LEFT, 0.25f, layout.getEditorArea());
+        left.addView(ThermostatConstants.VIEW_ID_HOST_VM);
+        
+        IFolderLayout right = layout.createFolder(FOLDER_RIGHT, IPageLayout.RIGHT, 0.5f, layout.getEditorArea());
+        right.addView(ThermostatConstants.VIEW_ID_HOST_OVERVIEW);
+        right.addView(ThermostatConstants.VIEW_ID_HOST_CPU);
+        right.addView(ThermostatConstants.VIEW_ID_HOST_MEMORY);
+        right.addView(ThermostatConstants.VIEW_ID_VM_CPU);
+        right.addView(ThermostatConstants.VIEW_ID_VM_GC);
+        
+        layout.setEditorAreaVisible(false);
+    }
+
+    private void defineActions(IPageLayout layout) {
+        layout.addShowViewShortcut(ThermostatConstants.VIEW_ID_HOST_VM);
+        layout.addShowViewShortcut(ThermostatConstants.VIEW_ID_HOST_OVERVIEW);
+        layout.addShowViewShortcut(ThermostatConstants.VIEW_ID_HOST_CPU);
+        layout.addShowViewShortcut(ThermostatConstants.VIEW_ID_HOST_MEMORY);
+        layout.addShowViewShortcut(ThermostatConstants.VIEW_ID_VM_CPU);
+        layout.addShowViewShortcut(ThermostatConstants.VIEW_ID_VM_GC);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/core-p2-repository/category.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<site>
+   <feature url="features/com.redhat.thermostat.client.feature_0.5.0.qualifier.jar" id="com.redhat.thermostat.client.feature" version="0.5.0.qualifier">
+      <category name="thermostat-client"/>
+   </feature>
+   <category-def name="thermostat-client" label="Thermostat Client"/>
+</site>
--- a/eclipse/core-p2-repository/pom.xml	Fri Oct 26 13:13:42 2012 +0200
+++ b/eclipse/core-p2-repository/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -1,41 +1,4 @@
 <?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 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <modelVersion>4.0.0</modelVersion>
@@ -48,168 +11,28 @@
   <artifactId>com.redhat.thermostat.eclipse.core-p2-repo</artifactId>
   <version>0.5.0-SNAPSHOT</version>
 
-  <name>Thermostat Core Bundles p2 Repository</name>
+  <name>Thermostat Client p2 Repository</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+      <artifactId>com.redhat.thermostat.client.feature</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
 
   <build>
     <plugins>
-      <!-- Configuration for the PublishFeaturesAndBundlesMojoTest -->
       <plugin>
-        <groupId>org.eclipse.tycho.extras</groupId>
-        <artifactId>tycho-p2-extras-plugin</artifactId>
+        <groupId>org.eclipse.tycho</groupId>
+        <artifactId>tycho-p2-publisher-plugin</artifactId>
         <version>${tycho-version}</version>
-        <executions>
-          <execution>
-            <phase>prepare-package</phase>
-            <goals>
-              <goal>publish-features-and-bundles</goal>
-            </goals>
-          </execution>
-        </executions>
         <configuration>
-          <compress>true</compress>
+          <publishArtifacts>true</publishArtifacts>
         </configuration>
       </plugin>
-      <plugin>
-        <artifactId>maven-dependency-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>copy-bundles-for-publishing</id>
-            <phase>process-resources</phase>
-            <goals>
-              <goal>copy</goal>
-            </goals>
-            <configuration>
-              <artifactItems>
-                <artifactItem>
-                  <groupId>com.redhat.thermostat</groupId>
-                  <artifactId>thermostat-main</artifactId>
-                  <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                  <groupId>com.redhat.thermostat</groupId>
-                  <artifactId>thermostat-bundles</artifactId>
-                  <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                  <groupId>com.redhat.thermostat</groupId>
-                  <artifactId>thermostat-tools</artifactId>
-                  <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                  <groupId>com.redhat.thermostat</groupId>
-                  <artifactId>thermostat-launcher</artifactId>
-                  <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                  <groupId>com.redhat.thermostat</groupId>
-                  <artifactId>thermostat-client-core</artifactId>
-                  <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                  <groupId>com.redhat.thermostat</groupId>
-                  <artifactId>thermostat-client-command</artifactId>
-                  <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                  <groupId>com.redhat.thermostat</groupId>
-                  <artifactId>thermostat-client-vmclassstat</artifactId>
-                  <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                  <groupId>com.redhat.thermostat</groupId>
-                  <artifactId>thermostat-osgi-memory-stats-panel</artifactId>
-                  <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                    <groupId>com.redhat.thermostat</groupId>
-                    <artifactId>thermostat-osgi-living-vm-filter</artifactId>
-                    <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                  <groupId>com.redhat.thermostat</groupId>
-                  <artifactId>thermostat-agent-core</artifactId>
-                  <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                  <groupId>com.redhat.thermostat</groupId>
-                  <artifactId>thermostat-agent-cli</artifactId>
-                  <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                  <groupId>com.redhat.thermostat</groupId>
-                  <artifactId>thermostat-agent-command</artifactId>
-                  <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                  <groupId>com.redhat.thermostat</groupId>
-                  <artifactId>thermostat-common-core</artifactId>
-                  <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                  <groupId>com.redhat.thermostat</groupId>
-                  <artifactId>thermostat-common-command</artifactId>
-                  <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                    <groupId>com.redhat.thermostat</groupId>
-                    <artifactId>thermostat-osgi-process-handler</artifactId>
-                    <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                    <groupId>com.redhat.thermostat</groupId>
-                    <artifactId>thermostat-killvm-client-swing</artifactId>
-                    <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                    <groupId>com.redhat.thermostat</groupId>
-                    <artifactId>thermostat-client-heapdumper</artifactId>
-                    <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                    <groupId>com.redhat.thermostat</groupId>
-                    <artifactId>thermostat-laf</artifactId>
-                    <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                    <groupId>com.redhat.thermostat</groupId>
-                    <artifactId>thermostat-swing-components</artifactId>
-                    <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                    <groupId>com.redhat.thermostat</groupId>
-                    <artifactId>thermostat-keyring</artifactId>
-                    <version>${project.version}</version>
-                </artifactItem>
-                
-                <!--  thread plugin -->
-                <artifactItem>
-                    <groupId>com.redhat.thermostat</groupId>
-                    <artifactId>thermostat-thread-client-common</artifactId>
-                    <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                    <groupId>com.redhat.thermostat</groupId>
-                    <artifactId>thermostat-thread-client-controllers</artifactId>
-                    <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                    <groupId>com.redhat.thermostat</groupId>
-                    <artifactId>thermostat-thread-client-swing</artifactId>
-                    <version>${project.version}</version>
-                </artifactItem>
-                <artifactItem>
-                    <groupId>com.redhat.thermostat</groupId>
-                    <artifactId>thermostat-thread-collector</artifactId>
-                    <version>${project.version}</version>
-                </artifactItem>      
-              </artifactItems>
-              <outputDirectory>${project.basedir}/target/source/plugins</outputDirectory>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
     </plugins>
   </build>
 
-  <packaging>pom</packaging>
+  <packaging>eclipse-repository</packaging>
 </project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/jfreechart-bundle-wrapping/org.jfree.chart/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,189 @@
+<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/maven-v4_0_0.xsd">
+
+<!-- 
+
+ 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.
+
+-->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+      <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+      <artifactId>thermostat-eclipse-jfreechart</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.jfree.chart</groupId>
+    <artifactId>com.redhat.thermostat.bundles.org.jfree.chart</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.0.14</version>
+    <name>Thermostat Eclipse :: Bundles :: ${pkgArtifactId}</name>
+    <description>
+        This bundle simply wraps ${pkgArtifactId}-${pkgVersion}.jar.
+    </description>
+
+    <properties>
+        <pkgGroupId>org.jfree</pkgGroupId>
+        <pkgArtifactId>jfreechart</pkgArtifactId>
+        <pkgVersion>1.0.14</pkgVersion>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>${pkgGroupId}</groupId>
+            <artifactId>${pkgArtifactId}</artifactId>
+            <version>${pkgVersion}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.felix</groupId>
+          <artifactId>maven-bundle-plugin</artifactId>
+          <extensions>true</extensions>
+          <configuration>
+            <instructions>
+              <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+              <Export-Package>
+                org.jfree.chart,
+                org.jfree.chart.annotations,
+                org.jfree.chart.axis,
+                org.jfree.chart.block,
+                org.jfree.chart.demo,
+                org.jfree.chart.editor,
+                org.jfree.chart.encoders,
+                org.jfree.chart.entity,
+                org.jfree.chart.event,
+                org.jfree.chart.imagemap,
+                org.jfree.chart.labels,
+                org.jfree.chart.needle,
+                org.jfree.chart.panel,
+                org.jfree.chart.plot,
+                org.jfree.chart.plot.dial,
+                org.jfree.chart.renderer,
+                org.jfree.chart.renderer.category,
+                org.jfree.chart.renderer.xy,
+                org.jfree.chart.resources,
+                org.jfree.chart.servlet,
+                org.jfree.chart.title,
+                org.jfree.chart.urls,
+                org.jfree.chart.util,
+                org.jfree.data,
+                org.jfree.data.category,
+                org.jfree.data.contour,
+                org.jfree.data.function,
+                org.jfree.data.gantt,
+                org.jfree.data.general,
+                org.jfree.data.io,
+                org.jfree.data.jdbc,
+                org.jfree.data.resources,
+                org.jfree.data.statistics,
+                org.jfree.data.time,
+                org.jfree.data.time.ohlc,
+                org.jfree.data.xml,
+                org.jfree.data.xy
+              </Export-Package>
+              <Import-Package>
+                com.keypoint;resolution:=optional,
+                javax.imageio;resolution:=optional,
+                javax.imageio.metadata;resolution:=optional,
+                javax.imageio.stream;resolution:=optional,
+                javax.servlet;resolution:=optional,
+                javax.servlet.http;resolution:=optional,
+                javax.swing;resolution:=optional,
+                javax.swing.border;resolution:=optional,
+                javax.swing.event;resolution:=optional,
+                javax.swing.filechooser;resolution:=optional,
+                javax.swing.table;resolution:=optional,
+                javax.xml.parsers;resolution:=optional,
+                org.jfree;resolution:=optional,
+                org.jfree.base;resolution:=optional,
+                org.jfree.chart;resolution:=optional,
+                org.jfree.chart.annotations;resolution:=optional,
+                org.jfree.chart.axis;resolution:=optional,
+                org.jfree.chart.block;resolution:=optional,
+                org.jfree.chart.demo;resolution:=optional,
+                org.jfree.chart.editor;resolution:=optional,
+                org.jfree.chart.encoders;resolution:=optional,
+                org.jfree.chart.entity;resolution:=optional,
+                org.jfree.chart.event;resolution:=optional,
+                org.jfree.chart.imagemap;resolution:=optional,
+                org.jfree.chart.labels;resolution:=optional,
+                org.jfree.chart.needle;resolution:=optional,
+                org.jfree.chart.panel;resolution:=optional,
+                org.jfree.chart.plot;resolution:=optional,
+                org.jfree.chart.plot.dial;resolution:=optional,
+                org.jfree.chart.renderer;resolution:=optional,
+                org.jfree.chart.renderer.category;resolution:=optional,
+                org.jfree.chart.renderer.xy;resolution:=optional,
+                org.jfree.chart.resources;resolution:=optional,
+                org.jfree.chart.servlet;resolution:=optional,
+                org.jfree.chart.title;resolution:=optional,
+                org.jfree.chart.urls;resolution:=optional,
+                org.jfree.chart.util;resolution:=optional,
+                org.jfree.data;resolution:=optional,
+                org.jfree.data.category;resolution:=optional,
+                org.jfree.data.contour;resolution:=optional,
+                org.jfree.data.function;resolution:=optional,
+                org.jfree.data.gantt;resolution:=optional,
+                org.jfree.data.general;resolution:=optional,
+                org.jfree.data.io;resolution:=optional,
+                org.jfree.data.jdbc;resolution:=optional,
+                org.jfree.data.resources;resolution:=optional,
+                org.jfree.data.statistics;resolution:=optional,
+                org.jfree.data.time;resolution:=optional,
+                org.jfree.data.time.ohlc;resolution:=optional,
+                org.jfree.data.xml;resolution:=optional,
+                org.jfree.data.xy;resolution:=optional,
+                org.jfree.date;resolution:=optional,
+                org.jfree.io;resolution:=optional,
+                org.jfree.layout;resolution:=optional,
+                org.jfree.text;resolution:=optional,
+                org.jfree.ui;resolution:=optional,
+                org.jfree.ui.about;resolution:=optional,
+                org.jfree.util;resolution:=optional,
+                org.xml.sax;resolution:=optional,
+                org.xml.sax.helpers;resolution:=optional
+              </Import-Package>
+              <_nouses>true</_nouses>
+            </instructions>
+          </configuration>
+        </plugin>
+      </plugins>
+    </build>
+
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/jfreechart-bundle-wrapping/org.jfree/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,136 @@
+<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/maven-v4_0_0.xsd">
+
+<!-- 
+
+ 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.
+
+-->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+      <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+      <artifactId>thermostat-eclipse-jfreechart</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.jfree</groupId>
+    <artifactId>com.redhat.thermostat.bundles.org.jfree</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.0.17</version>
+    <name>Thermostat Eclipse :: Bundles :: ${pkgArtifactId}</name>
+    <description>
+        This bundle simply wraps ${pkgArtifactId}-${pkgVersion}.jar.
+    </description>
+
+    <properties>
+        <pkgGroupId>org.jfree</pkgGroupId>
+        <pkgArtifactId>jcommon</pkgArtifactId>
+        <pkgVersion>1.0.17</pkgVersion>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>${pkgGroupId}</groupId>
+            <artifactId>${pkgArtifactId}</artifactId>
+            <version>${pkgVersion}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.felix</groupId>
+          <artifactId>maven-bundle-plugin</artifactId>
+          <extensions>true</extensions>
+          <configuration>
+            <instructions>
+              <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+              <Export-Package>
+                com.keypoint,
+                org.jfree,
+                org.jfree.base,
+                org.jfree.base.config,
+                org.jfree.base.log,
+                org.jfree.base.modules,
+                org.jfree.date,
+                org.jfree.io,
+                org.jfree.layout,
+                org.jfree.resources,
+                org.jfree.text,
+                org.jfree.threads,
+                org.jfree.ui,
+                org.jfree.ui.about,
+                org.jfree.ui.about.resources,
+                org.jfree.ui.action,
+                org.jfree.ui.tabbedui,
+                org.jfree.util 
+              </Export-Package>
+              <Import-Package>
+                com.keypoint;resolution:=optional,
+                javax.accessibility;resolution:=optional,
+                javax.swing;resolution:=optional,
+                javax.swing.border;resolution:=optional,
+                javax.swing.event;resolution:=optional,
+                javax.swing.filechooser;resolution:=optional,
+                javax.swing.plaf;resolution:=optional,
+                javax.swing.table;resolution:=optional,
+                javax.swing.text;resolution:=optional,
+                org.jfree;resolution:=optional,
+                org.jfree.base;resolution:=optional,
+                org.jfree.base.config;resolution:=optional,
+                org.jfree.base.log;resolution:=optional,
+                org.jfree.base.modules;resolution:=optional,
+                org.jfree.date;resolution:=optional,
+                org.jfree.io;resolution:=optional,
+                org.jfree.layout;resolution:=optional,
+                org.jfree.resources;resolution:=optional,
+                org.jfree.text;resolution:=optional,
+                org.jfree.threads;resolution:=optional,
+                org.jfree.ui;resolution:=optional,
+                org.jfree.ui.about;resolution:=optional,
+                org.jfree.ui.about.resources;resolution:=optional,
+                org.jfree.ui.action;resolution:=optional,
+                org.jfree.ui.tabbedui;resolution:=optional,
+                org.jfree.util;resolution:=optional
+              </Import-Package>
+              <_nouses>true</_nouses>
+            </instructions>
+          </configuration>
+        </plugin>
+      </plugins>
+    </build>
+
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/jfreechart-bundle-wrapping/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,57 @@
+<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/maven-v4_0_0.xsd">
+<!-- 
+
+ 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.
+
+-->
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+      <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+      <artifactId>thermostat-eclipse-parent</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>thermostat-eclipse-jfreechart</artifactId>
+    <packaging>pom</packaging>
+
+    <name>Thermostat Eclipse :: JFreeChart :: Bundles</name>
+
+    <modules>
+      <module>org.jfree</module>
+      <module>org.jfree.chart</module>
+    </modules>
+
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eclipse/jfreechart-p2-repository/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,103 @@
+<?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 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>thermostat-eclipse-parent</artifactId>
+    <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+  <groupId>com.redhat.thermostat.eclipse.parent</groupId>
+  <artifactId>com.redhat.thermostat.eclipse.jfreechart-repo</artifactId>
+  <version>0.5.0-SNAPSHOT</version>
+
+  <name>Thermostat Eclipse :: p2 repository for JFreeChart</name>
+
+  <build>
+    <plugins>
+      <!-- Configuration for the PublishFeaturesAndBundlesMojoTest -->
+      <plugin>
+        <groupId>org.eclipse.tycho.extras</groupId>
+        <artifactId>tycho-p2-extras-plugin</artifactId>
+        <version>${tycho-version}</version>
+        <executions>
+          <execution>
+            <phase>prepare-package</phase>
+            <goals>
+              <goal>publish-features-and-bundles</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <compress>true</compress>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy-bundles-for-publishing</id>
+            <phase>process-resources</phase>
+            <goals>
+              <goal>copy</goal>
+            </goals>
+            <configuration>
+              <artifactItems>
+                <artifactItem>
+                  <groupId>org.jfree</groupId>
+                  <artifactId>com.redhat.thermostat.bundles.org.jfree</artifactId>
+                  <version>1.0.17</version>
+                </artifactItem>
+                <artifactItem>
+                  <groupId>org.jfree.chart</groupId>
+                  <artifactId>com.redhat.thermostat.bundles.org.jfree.chart</artifactId>
+                  <version>1.0.14</version>
+                </artifactItem>
+              </artifactItems>
+              <outputDirectory>${project.basedir}/target/source/plugins</outputDirectory>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+  <packaging>pom</packaging>
+</project>
--- a/eclipse/pom.xml	Fri Oct 26 13:13:42 2012 +0200
+++ b/eclipse/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -91,15 +91,20 @@
   <modules>
     <module>com.redhat.thermostat.eclipse.boot</module>
     <module>com.redhat.thermostat.eclipse</module>
+    <module>com.redhat.thermostat.eclipse.chart.common</module>
     <module>com.redhat.thermostat.eclipse.test</module>
+    <module>com.redhat.thermostat.eclipse.test.ui</module>
     <module>com.redhat.thermostat.eclipse.feature</module>
     <module>com.redhat.thermostat.eclipse.p2-repo</module>
+    <module>com.redhat.thermostat.client.feature</module>
     <module>core-p2-repository</module>
     <module>test-deps-bundle-wrapping</module>
+    <module>jfreechart-bundle-wrapping</module>
     <!-- Adds p2 metadata and creates repo for plain (wrapped)
          Java OSGi bundles so they can be found for building and
          running tycho tests -->
     <module>test-deps-p2-repository</module>
+    <module>jfreechart-p2-repository</module>
     <module>composite-repo</module>
   </modules>
 
@@ -120,6 +125,11 @@
       <url>file://${basedir}/../test-deps-p2-repository/target/repository/</url>
     </repository>
     <repository>
+      <id>local_jfreechart</id>
+      <layout>p2</layout>
+      <url>file://${basedir}/../jfreechart-p2-repository/target/repository/</url>
+    </repository>
+    <repository>
       <id>maven.eclipse.org</id>
       <url>http://maven.eclipse.org/nexus/content/groups/public/</url>
     </repository>
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/DbServiceFactory.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/DbServiceFactory.java	Fri Oct 26 15:32:56 2012 +0200
@@ -44,7 +44,7 @@
  */
 public class DbServiceFactory {
 
-    public static DbService createDbService(String username, String password, String dbUrl) {
+    public DbService createDbService(String username, String password, String dbUrl) {
         return DbServiceImpl.create(username, password, dbUrl);
     }
 }
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/CommandInfoSourceImpl.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/CommandInfoSourceImpl.java	Fri Oct 26 15:32:56 2012 +0200
@@ -47,6 +47,7 @@
 import java.util.logging.Logger;
 
 import com.redhat.thermostat.common.cli.CommandInfo;
+import com.redhat.thermostat.common.cli.CommandInfoNotFoundException;
 import com.redhat.thermostat.common.cli.CommandInfoSource;
 
 public class CommandInfoSourceImpl implements CommandInfoSource {
@@ -92,10 +93,16 @@
         return fileName.substring(0, dotIndex);
     }
 
-    public CommandInfo getCommandInfo(String name) {
-        return commands.get(name);
+    @Override
+    public CommandInfo getCommandInfo(String name) throws CommandInfoNotFoundException {
+        CommandInfo cmdInfo = commands.get(name);
+        if (cmdInfo == null) {
+            throw new CommandInfoNotFoundException(name);
+        }
+        return cmdInfo;
     }
 
+    @Override
     public Collection<CommandInfo> getCommandInfos() {
         return commands.values();
     }
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/HelpCommand.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/HelpCommand.java	Fri Oct 26 15:32:56 2012 +0200
@@ -52,13 +52,17 @@
 import com.redhat.thermostat.common.cli.Arguments;
 import com.redhat.thermostat.common.cli.CommandContext;
 import com.redhat.thermostat.common.cli.CommandInfo;
+import com.redhat.thermostat.common.cli.CommandInfoNotFoundException;
 import com.redhat.thermostat.common.cli.CommandInfoSource;
 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.launcher.CommonCommandOptions;
 
 public class HelpCommand extends SimpleCommand {
 
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
     private static final int COMMANDS_COLUMNS_WIDTH = 14;
     private static final String NAME = "help";
 
@@ -79,7 +83,7 @@
         BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext();
         ServiceReference infosRef = context.getServiceReference(CommandInfoSource.class);
         CommandInfoSource infos = (CommandInfoSource) context.getService(infosRef);
-        ctx.getConsole().getOutput().print("list of commands:\n\n");
+        ctx.getConsole().getOutput().print(translator.localize(LocaleResources.COMMAND_HELP_COMMAND_LIST_HEADER));
 
         TableRenderer renderer = new TableRenderer(2, COMMANDS_COLUMNS_WIDTH);
 
@@ -102,12 +106,14 @@
         BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext();
         ServiceReference infosRef = context.getServiceReference(CommandInfoSource.class);
         CommandInfoSource infos = (CommandInfoSource) context.getService(infosRef);
-        CommandInfo info = infos.getCommandInfo(cmdName);
-        context.ungetService(infosRef);
-        if (info != null) {
+        try {
+            CommandInfo info = infos.getCommandInfo(cmdName);
             printHelp(ctx, info);
-        } else {
+        } catch (CommandInfoNotFoundException notFound) {
+            ctx.getConsole().getOutput().print(translator.localize(LocaleResources.UNKNOWN_COMMAND, cmdName));
             printCommandSummaries(ctx);
+        } finally {
+            context.ungetService(infosRef);
         }
     }
 
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java	Fri Oct 26 15:32:56 2012 +0200
@@ -46,6 +46,7 @@
 import org.apache.commons.cli.Options;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleException;
+import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 
 import com.redhat.thermostat.bundles.OSGiRegistry;
@@ -59,6 +60,7 @@
 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.CommandInfoNotFoundException;
 import com.redhat.thermostat.common.cli.CommandRegistry;
 import com.redhat.thermostat.common.config.ClientPreferences;
 import com.redhat.thermostat.common.config.InvalidConfigurationException;
@@ -66,7 +68,6 @@
 import com.redhat.thermostat.common.tools.ApplicationState;
 import com.redhat.thermostat.common.tools.BasicCommand;
 import com.redhat.thermostat.common.utils.LoggingUtils;
-import com.redhat.thermostat.common.utils.OSGIUtils;
 import com.redhat.thermostat.launcher.CommonCommandOptions;
 import com.redhat.thermostat.launcher.DbService;
 import com.redhat.thermostat.launcher.DbServiceFactory;
@@ -75,8 +76,6 @@
 
 public class LauncherImpl implements Launcher {
 
-    private static final String UNKNOWN_COMMAND_MESSAGE = "unknown command '%s'\n";
-
     private ClientPreferences prefs;
 
     private String[] args;
@@ -88,12 +87,20 @@
 
     private BundleContext context;
     private OSGiRegistry registry;
+    private final DbServiceFactory dbServiceFactory;
     
-    public LauncherImpl(BundleContext context, CommandContextFactory cmdCtxFactory,
-            OSGiRegistry registry) {
+    public LauncherImpl(BundleContext context, CommandContextFactory cmdCtxFactory, OSGiRegistry registry) {
+        this(context, cmdCtxFactory, registry, new LoggingInitializer(), new DbServiceFactory());
+    }
+
+    LauncherImpl(BundleContext context, CommandContextFactory cmdCtxFactory, OSGiRegistry registry,
+            LoggingInitializer loggingInitializer, DbServiceFactory dbServiceFactory) {
         this.context = context;
         this.cmdCtxFactory = cmdCtxFactory;
         this.registry = registry;
+        this.dbServiceFactory = dbServiceFactory;
+
+        loggingInitializer.initialize();
     }
 
     @Override
@@ -104,14 +111,9 @@
     @Override
     public synchronized void run(Collection<ActionListener<ApplicationState>> listeners) {
         usageCount++;
+        waitForArgs();
+
         try {
-            argsBarrier.acquire();
-        } catch (InterruptedException e) {
-            e.printStackTrace();
-        }
-        try {
-            // TODO move this logging init out where it's not part of every command launch
-            initLogging();
             if (hasNoArguments()) {
                 runHelpCommand();
             } else if (isVersionQuery()) {
@@ -137,6 +139,14 @@
         argsBarrier.release();
     }
 
+    private void waitForArgs() {
+        try {
+            argsBarrier.acquire();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
     private boolean isLastLaunch() {
         return usageCount == 0;
     }
@@ -157,19 +167,6 @@
         this.prefs = prefs;
     }
 
-    private void initLogging() {
-        try {
-            LoggingUtils.loadGlobalLoggingConfig();
-        } catch (InvalidConfigurationException e) {
-            System.err.println("WARNING: Could not read global Thermostat logging configuration.");
-        }
-        try {
-            LoggingUtils.loadUserLoggingConfig();
-        } catch (InvalidConfigurationException e) {
-            // We intentionally ignore this.
-        }
-    }
-
     private boolean hasNoArguments() {
         return args.length == 0;
     }
@@ -178,6 +175,10 @@
         runCommand("help", new String[0], null);
     }
 
+    private void runHelpCommandFor(String cmdName) {
+        runCommand("help", new String[] { "--", cmdName }, null);
+    }
+
     private void runCommandFromArguments(Collection<ActionListener<ApplicationState>> listeners) {
         runCommand(args[0], Arrays.copyOfRange(args, 1, args.length), listeners);
     }
@@ -201,12 +202,14 @@
             out.println("Could not load necessary bundles for: " + cmdName);
             e.printStackTrace(out);
             return;
+        } catch (CommandInfoNotFoundException commandNotFound) {
+            runHelpCommandFor(cmdName);
+            return;
         }
 
         Command cmd = getCommand(cmdName);
         if (cmd == null) {
-            out.print(String.format(UNKNOWN_COMMAND_MESSAGE, cmdName));
-            runHelpCommand();
+            runHelpCommandFor(cmdName);
             return;
         }
         if (listeners != null && cmd instanceof BasicCommand) {
@@ -262,25 +265,27 @@
         CommandContext ctx = cmdCtxFactory.createContext(args);
         
         if (prefs == null) {
-            prefs = new ClientPreferences(OSGIUtils.getInstance().getService(Keyring.class));
+            ServiceReference keyringReference = context.getServiceReference(Keyring.class);
+            Keyring keyring = (Keyring) context.getService(keyringReference);
+            prefs = new ClientPreferences(keyring);
         }
         
         if (cmd.isStorageRequired()) {
-            DbService service = OSGIUtils.getInstance().getServiceAllowNull(DbService.class);
-            if (service == null) {
+            ServiceReference dbServiceReference = context.getServiceReference(DbService.class);
+            if (dbServiceReference == null) {
                 String dbUrl = ctx.getArguments().getArgument(CommonCommandOptions.DB_URL_ARG);
                 if (dbUrl == null) {
                     dbUrl = prefs.getConnectionUrl();
                 }
                 String username = ctx.getArguments().getArgument(CommonCommandOptions.USERNAME_ARG);
                 String password = ctx.getArguments().getArgument(CommonCommandOptions.PASSWORD_ARG);
-                service = DbServiceFactory.createDbService(username, password, dbUrl);
+                DbService service = dbServiceFactory.createDbService(username, password, dbUrl);
                 try {
                     service.connect();
                 } catch (ConnectionException ex) {
                     throw new CommandException("Could not connect to: " + dbUrl, ex);
                 }
-                ServiceRegistration registration = OSGIUtils.getInstance().registerService(DbService.class, service);
+                ServiceRegistration registration = context.registerService(DbService.class, service, null);
                 service.setServiceRegistration(registration);
             }
         }
@@ -291,4 +296,18 @@
         return args[0].equals(Version.VERSION_OPTION);
     }
 
+    static class LoggingInitializer {
+        public void initialize() {
+            try {
+                LoggingUtils.loadGlobalLoggingConfig();
+            } catch (InvalidConfigurationException e) {
+                System.err.println("WARNING: Could not read global Thermostat logging configuration.");
+            }
+            try {
+                LoggingUtils.loadUserLoggingConfig();
+            } catch (InvalidConfigurationException e) {
+                // We intentionally ignore this.
+            }
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LocaleResources.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,52 @@
+/*
+ * 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.launcher.internal;
+
+import com.redhat.thermostat.common.locale.Translate;
+
+public enum LocaleResources {
+
+    UNKNOWN_COMMAND,
+    COMMAND_HELP_COMMAND_LIST_HEADER,
+    ;
+
+    static final String RESOURCE_BUNDLE = "com.redhat.thermostat.launcher.internal.strings";
+
+    public static Translate<LocaleResources> createLocalizer() {
+        return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/launcher/src/main/resources/META-INF/p2.inf	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,7 @@
+# Instructs Eclipse update manager to auto-start this bundle
+instructions.configure = \
+org.eclipse.equinox.p2.touchpoint.eclipse.setStartLevel(startLevel: 4); \
+org.eclipse.equinox.p2.touchpoint.eclipse.markStarted(started: true);
+instructions.unconfigure = \
+org.eclipse.equinox.p2.touchpoint.eclipse.setStartLevel(startLevel: -1); \
+org.eclipse.equinox.p2.touchpoint.eclipse.markStarted(started: false);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/launcher/src/main/resources/com/redhat/thermostat/launcher/internal/strings.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,3 @@
+UNKNOWN_COMMAND = unknown command ''{0}''\n
+
+COMMAND_HELP_COMMAND_LIST_HEADER = list of commands:\n\n
\ No newline at end of file
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/LauncherTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,463 +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.launcher;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.isA;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import static org.mockito.Matchers.any;
-
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-
-import com.redhat.thermostat.bundles.OSGiRegistry;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.ActionNotifier;
-import com.redhat.thermostat.common.ApplicationInfo;
-import com.redhat.thermostat.common.Version;
-import com.redhat.thermostat.common.appctx.ApplicationContext;
-import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
-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.CommandInfo;
-import com.redhat.thermostat.common.cli.CommandInfoSource;
-import com.redhat.thermostat.common.config.ClientPreferences;
-import com.redhat.thermostat.common.locale.LocaleResources;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.tools.ApplicationState;
-import com.redhat.thermostat.common.tools.BasicCommand;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-import com.redhat.thermostat.launcher.internal.HelpCommand;
-import com.redhat.thermostat.launcher.internal.LauncherImpl;
-import com.redhat.thermostat.test.TestCommandContextFactory;
-import com.redhat.thermostat.test.TestTimerFactory;
-import com.redhat.thermostat.test.cli.TestCommand;
-import com.redhat.thermostat.utils.keyring.Keyring;
-import com.redhat.thermostat.utils.keyring.KeyringProvider;
-
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({FrameworkUtil.class, DbServiceFactory.class, HelpCommand.class})
-public class LauncherTest {
-    
-    private static String defaultKeyringProvider;
-    private static final String name1 = "test1";
-    private static final String name2 = "test2";
-    private static final String name3 = "test3";
-      
-    @BeforeClass
-    public static void beforeClassSetUp() {
-        defaultKeyringProvider = System.getProperty(KeyringProvider.KEYRING_FACTORY_PROPERTY);
-    }
-    
-    @AfterClass
-    public static void afterClassTearDown() {
-        if (defaultKeyringProvider != null) {
-            System.setProperty(KeyringProvider.KEYRING_FACTORY_PROPERTY, defaultKeyringProvider);
-        }
-    }
-    
-    private static class TestCmd1 implements TestCommand.Handle {
-
-        @Override
-        public void run(CommandContext ctx) {
-            Arguments args = ctx.getArguments();
-            ctx.getConsole().getOutput().print(args.getArgument("arg1") + ", " + args.getArgument("arg2"));
-        }
-    }
-
-    private static class TestCmd2 implements TestCommand.Handle {
-        @Override
-        public void run(CommandContext ctx) {
-            Arguments args = ctx.getArguments();
-            ctx.getConsole().getOutput().print(args.getArgument("arg4") + ": " + args.getArgument("arg3"));
-        }
-    }
-
-    private TestCommandContextFactory  ctxFactory;
-    private BundleContext bundleContext;
-    private TestTimerFactory timerFactory;
-    private OSGiRegistry registry;
-    private ActionNotifier<ApplicationState> notifier;
-
-    @Before
-    public void setUp() {
-
-        ApplicationContextUtil.resetApplicationContext();
-        timerFactory = new TestTimerFactory();
-        ApplicationContext.getInstance().setTimerFactory(timerFactory);
-        setupCommandContextFactory();
-
-        TestCommand cmd1 = new TestCommand(name1, new TestCmd1());
-        CommandInfo info1 = mock(CommandInfo.class);
-        when(info1.getName()).thenReturn(name1);
-        Options options1 = new Options();
-        Option opt1 = new Option(null, "arg1", true, null);
-        options1.addOption(opt1);
-        Option opt2 = new Option(null, "arg2", true, null);
-        options1.addOption(opt2);
-        cmd1.addOptions(opt1, opt2);
-        cmd1.setDescription("description 1");
-        when(info1.getDescription()).thenReturn("description 1");
-        when(info1.getOptions()).thenReturn(options1);
-        TestCommand cmd2 = new TestCommand("test2", new TestCmd2());
-        CommandInfo info2 = mock(CommandInfo.class);
-        when(info2.getName()).thenReturn(name2);
-        Options options2 = new Options();
-        Option opt3 = new Option(null, "arg3", true, null);
-        options2.addOption(opt3);
-        Option opt4 = new Option(null, "arg4", true, null);
-        options2.addOption(opt4);
-        cmd2.addOptions(opt3, opt4);
-        cmd2.setDescription("description 2");
-        when(info2.getDescription()).thenReturn("description 2");
-        when(info2.getOptions()).thenReturn(options2);
-
-        TestCommand cmd3 = new TestCommand(name3);
-        CommandInfo info3 = mock(CommandInfo.class);
-        when(info3.getName()).thenReturn(name3);
-        cmd3.setStorageRequired(true);
-        cmd3.setDescription("description 3");
-        when(info3.getDescription()).thenReturn("description 3");
-        when(info3.getOptions()).thenReturn(new Options());
-
-        BasicCommand basicCmd = mock(BasicCommand.class);
-        CommandInfo basicInfo = mock(CommandInfo.class);
-        when(basicCmd.getName()).thenReturn("basic");
-        when(basicInfo.getName()).thenReturn("basic");
-        when(basicCmd.getDescription()).thenReturn("nothing that means anything");
-        when(basicInfo.getDescription()).thenReturn("nothing that means anything");
-        when(basicCmd.isStorageRequired()).thenReturn(false);
-        Options options = new Options();
-        when(basicCmd.getOptions()).thenReturn(options);
-        when(basicInfo.getOptions()).thenReturn(options);
-        notifier = mock(ActionNotifier.class);
-        when(basicCmd.getNotifier()).thenReturn(notifier);
-        CommandInfo helpCommandInfo = mock(CommandInfo.class);
-        when(helpCommandInfo.getName()).thenReturn("help");
-        when(helpCommandInfo.getDescription()).thenReturn("print help information");
-        when(helpCommandInfo.getDependencyResourceNames()).thenReturn(new ArrayList<String>());
-        when(helpCommandInfo.getOptions()).thenReturn(new Options());
-        when(helpCommandInfo.getUsage()).thenReturn("thermostat help");
-
-        ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(new HelpCommand(), cmd1, cmd2, cmd3, basicCmd));
-
-        registry = mock(OSGiRegistry.class);
-
-        CommandInfoSource infos = mock(CommandInfoSource.class);
-        when(infos.getCommandInfo(name1)).thenReturn(info1);
-        when(infos.getCommandInfo(name2)).thenReturn(info2);
-        when(infos.getCommandInfo(name3)).thenReturn(info3);
-        when(infos.getCommandInfo("basic")).thenReturn(basicInfo);
-        when(infos.getCommandInfo("help")).thenReturn(helpCommandInfo);
-        Collection<CommandInfo> infoList = new ArrayList<CommandInfo>();
-        infoList.add(helpCommandInfo);
-        infoList.add(basicInfo);
-        infoList.add(info1);
-        infoList.add(info2);
-        infoList.add(info3);
-        when(infos.getCommandInfos()).thenReturn(infoList);
-
-        PowerMockito.mockStatic(FrameworkUtil.class);
-        Bundle bundle = mock(Bundle.class);
-        BundleContext bCtx = mock(BundleContext.class);
-        when(bundle.getBundleContext()).thenReturn(bCtx);
-        ServiceReference infosRef = mock(ServiceReference.class);
-        when(bCtx.getServiceReference(CommandInfoSource.class)).thenReturn(infosRef);
-        when(bCtx.getService(infosRef)).thenReturn(infos);
-        when(FrameworkUtil.getBundle(isA(HelpCommand.class.getClass()))).thenReturn(bundle);
-    }
-
-    private void setupCommandContextFactory() {
-        Bundle sysBundle = mock(Bundle.class);
-        bundleContext = mock(BundleContext.class);
-        when(bundleContext.getBundle(0)).thenReturn(sysBundle);
-        ctxFactory = new TestCommandContextFactory(bundleContext);
-    }
-
-
-    @After
-    public void tearDown() {
-        ctxFactory = null;
-        ApplicationContextUtil.resetApplicationContext();
-    }
-
-    @Test
-    public void testMain() {
-        runAndVerifyCommand(new String[] {name1, "--arg1", "Hello", "--arg2", "World"}, "Hello, World");
-
-        ctxFactory.reset();
-
-        runAndVerifyCommand(new String[] {"test2", "--arg3", "Hello", "--arg4", "World"}, "World: Hello");
-    }
-
-    @Test
-    public void testMainNoArgs() {
-        String expected = "list of commands:\n\n"
-                        + " help          print help information\n"
-                        + " basic         nothing that means anything\n"
-                        + " test1         description 1\n"
-                        + " test2         description 2\n"
-                        + " test3         description 3\n";
-        runAndVerifyCommand(new String[0], expected);
-    }
-
-    @Test
-    public void verifySetLogLevel() {
-        runAndVerifyCommand(new String[] {name1, "--logLevel", "WARNING", "--arg1", "Hello", "--arg2", "World"}, "Hello, World");
-        Logger globalLogger = Logger.getLogger("com.redhat.thermostat");
-        assertEquals(Level.WARNING, globalLogger.getLevel());
-    }
-
-    @Test
-    public void testMainBadCommand1() {
-        String expected = "unknown command '--help'\n"
-            + "list of commands:\n\n"
-            + " help          print help information\n"
-            + " basic         nothing that means anything\n"
-            + " test1         description 1\n"
-            + " test2         description 2\n"
-            + " test3         description 3\n";
-        runAndVerifyCommand(new String[] {"--help"}, expected);
-    }
-
-    @Test
-    public void testMainBadCommand2() {
-        String expected = "unknown command '-help'\n"
-            + "list of commands:\n\n"
-            + " help          print help information\n"
-            + " basic         nothing that means anything\n"
-            + " test1         description 1\n"
-            + " test2         description 2\n"
-            + " test3         description 3\n";
-        runAndVerifyCommand(new String[] {"-help"}, expected);
-    }
-
-    @Test
-    public void testMainBadCommand3() {
-        String expected = "unknown command 'foobarbaz'\n"
-            + "list of commands:\n\n"
-            + " help          print help information\n"
-            + " basic         nothing that means anything\n"
-            + " test1         description 1\n"
-            + " test2         description 2\n"
-            + " test3         description 3\n";
-        runAndVerifyCommand(new String[] {"foobarbaz"}, expected);
-    }
-
-    @Test
-    public void testMainBadCommand4() {
-        String expected = "unknown command 'foo'\n"
-            + "list of commands:\n\n"
-            + " help          print help information\n"
-            + " basic         nothing that means anything\n"
-            + " test1         description 1\n"
-            + " test2         description 2\n"
-            + " test3         description 3\n";
-        runAndVerifyCommand(new String[] {"foo",  "--bar", "baz"}, expected);
-    }
-
-    @Test
-    public void testMainExceptionInCommand() {
-        TestCommand errorCmd = new TestCommand("error", new TestCommand.Handle() {
-
-            @Override
-            public void run(CommandContext ctx) throws CommandException {
-                throw new CommandException("test error");
-            }
-
-        });
-        ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(errorCmd));
-
-        LauncherImpl launcher = new LauncherImpl(bundleContext, ctxFactory, registry);
-        Keyring keyring = mock(Keyring.class);
-        launcher.setPreferences(new ClientPreferences(keyring));
-        launcher.setArgs(new String[] { "error" });
-        launcher.run();
-        assertEquals("test error\n", ctxFactory.getError());
-
-    }
-
-    private void runAndVerifyCommand(String[] args, String expected) {
-        LauncherImpl launcher = new LauncherImpl(bundleContext, ctxFactory, registry);
-        
-        Keyring keyring = mock(Keyring.class);
-        launcher.setPreferences(new ClientPreferences(keyring));
-        launcher.setArgs(args);
-        launcher.run();
-        assertEquals(expected, ctxFactory.getOutput());
-        assertTrue(timerFactory.isShutdown());
-    }
-
-    @Test
-    public void verifyStorageCommandSetsUpDAOFactory() {
-        LauncherImpl launcher = new LauncherImpl(bundleContext, ctxFactory, registry);
-        Keyring keyring = mock(Keyring.class);
-        Bundle sysBundle = mock(Bundle.class);
-        PowerMockito.mockStatic(FrameworkUtil.class);
-        when(FrameworkUtil.getBundle(OSGIUtils.class)).thenReturn(sysBundle);
-        when(sysBundle.getBundleContext()).thenReturn(bundleContext);
-        PowerMockito.mockStatic(DbServiceFactory.class);
-        String dbUrl = "mongo://fluff:12345";
-        DbService dbService = mock(DbService.class);
-        when(DbServiceFactory.createDbService(null, null, dbUrl)).thenReturn(dbService);
-        launcher.setPreferences(new ClientPreferences(keyring));
-        
-        launcher.setArgs(new String[] { "test3" , "--dbUrl", dbUrl });
-        launcher.run();
-        verify(dbService).connect();
-        verify(dbService).setServiceRegistration(any(ServiceRegistration.class));
-    }
-
-    @Test
-    public void verifyStorageCommandSetsUpDAOFactoryWithAuth() {
-        LauncherImpl launcher = new LauncherImpl(bundleContext, ctxFactory, registry);
-        Keyring keyring = mock(Keyring.class);
-        Bundle sysBundle = mock(Bundle.class);
-        PowerMockito.mockStatic(FrameworkUtil.class);
-        when(FrameworkUtil.getBundle(OSGIUtils.class)).thenReturn(sysBundle);
-        when(sysBundle.getBundleContext()).thenReturn(bundleContext);
-        PowerMockito.mockStatic(DbServiceFactory.class);
-        String dbUrl = "mongo://fluff:12345";
-        String testUser = "testUser";
-        String testPasswd = "testPassword";
-        DbService dbService = mock(DbService.class);
-        when(DbServiceFactory.createDbService(testUser, testPasswd, dbUrl)).thenReturn(dbService);
-        
-        launcher.setPreferences(new ClientPreferences(keyring));
-        
-        launcher.setArgs(new String[] { "test3" , "--dbUrl", dbUrl, "--username", testUser, "--password", testPasswd });
-        launcher.run();
-        verify(dbService).connect();
-        verify(dbService).setServiceRegistration(any(ServiceRegistration.class));
-    }
-
-    public void verifyPrefsAreUsed() {
-        ClientPreferences prefs = mock(ClientPreferences.class);
-        String dbUrl = "mongo://fluff:12345";
-        when(prefs.getConnectionUrl()).thenReturn(dbUrl);
-        LauncherImpl l = new LauncherImpl(bundleContext, ctxFactory, registry);
-        Bundle sysBundle = mock(Bundle.class);
-        PowerMockito.mockStatic(FrameworkUtil.class);
-        when(FrameworkUtil.getBundle(OSGIUtils.class)).thenReturn(sysBundle);
-        when(sysBundle.getBundleContext()).thenReturn(bundleContext);
-        PowerMockito.mockStatic(DbServiceFactory.class);
-        DbService dbService = mock(DbService.class);
-        // this makes sure that dbUrl is indeed retrieved from preferences
-        when(DbServiceFactory.createDbService(null, null, dbUrl)).thenReturn(dbService);
-        l.setPreferences(prefs);
-        l.setArgs(new String[] { "test3" });
-        l.run();
-        verify(dbService).connect();
-        verify(dbService).setServiceRegistration(any(ServiceRegistration.class));
-    }
-    
-    @Test
-    public void verifyVersionInfoQuery() {
-        int major = 0;
-        int minor = 3;
-        int micro = 0;
-        
-        ApplicationInfo appInfo = new ApplicationInfo();
-        Translate<LocaleResources> t = LocaleResources.createLocalizer();
-        String format = MessageFormat.format(
-                t.localize(LocaleResources.APPLICATION_VERSION_INFO),
-                appInfo.getName())
-                + " " + Version.VERSION_NUMBER_FORMAT;
-        
-        String expectedVersionInfo = String.format(format,
-                major, minor, micro) + "\n";
-        
-        String qualifier = "201207241700";
-        Bundle sysBundle = mock(Bundle.class);
-        Bundle framework = mock(Bundle.class);
-        org.osgi.framework.Version ver = org.osgi.framework.Version
-                .parseVersion(String.format(Version.VERSION_NUMBER_FORMAT,
-                        major, minor, micro) + "." + qualifier);
-        when(sysBundle.getVersion()).thenReturn(ver);
-        bundleContext = mock(BundleContext.class);
-        when(bundleContext.getBundle(0)).thenReturn(framework);
-        
-        PowerMockito.mockStatic(FrameworkUtil.class);
-        when(FrameworkUtil.getBundle(Version.class)).thenReturn(sysBundle);
-        LauncherImpl launcher = new LauncherImpl(bundleContext, ctxFactory, registry);
-        
-        launcher.setArgs(new String[] {Version.VERSION_OPTION});
-        launcher.run();
-        assertEquals(expectedVersionInfo, ctxFactory.getOutput());
-        assertTrue(timerFactory.isShutdown());
-    }
-
-    @Test
-    public void verifyListenersAdded() {
-        ActionListener<ApplicationState> listener = mock(ActionListener.class);
-        Collection<ActionListener<ApplicationState>> listeners = new ArrayList<>();
-        listeners.add(listener);
-        String[] args = new String[] {"basic"};
-        LauncherImpl launcher = new LauncherImpl(bundleContext, ctxFactory, registry);
-        Keyring keyring = mock(Keyring.class);
-        launcher.setPreferences(new ClientPreferences(keyring));
-
-        launcher.setArgs(args);
-        launcher.run(listeners);
-        verify(notifier).addActionListener(listener);
-    }
-}
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/CommandLineArgumentsParserTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/CommandLineArgumentsParserTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -37,6 +37,7 @@
 package com.redhat.thermostat.launcher.internal;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -148,4 +149,21 @@
     public void testMissingAdditionalArgument() throws CommandLineArgumentParseException {
         parser.parse(new String[] { "--test3" });
     }
+
+    @Test(expected = CommandLineArgumentParseException.class)
+    public void testRequiredArgumentEscaped() throws CommandLineArgumentParseException {
+        String[] rawArgs = new String[] { "--", "-t" };
+        parser.parse(rawArgs);
+    }
+
+    @Test
+    public void testEscapedArguments() throws CommandLineArgumentParseException {
+        String[] rawArgs = new String[] { "-t", "--", "--this-is-not-an-option" };
+        Arguments args = parser.parse(rawArgs);
+
+        assertTrue(args.hasArgument("t"));
+        assertFalse(args.hasArgument("--this-is-not-an-option"));
+        assertEquals("--this-is-not-an-option", args.getNonOptionArguments().get(0));
+    }
+
 }
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/HelpCommandTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/HelpCommandTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -61,7 +61,9 @@
 
 import com.redhat.thermostat.common.cli.Arguments;
 import com.redhat.thermostat.common.cli.CommandInfo;
+import com.redhat.thermostat.common.cli.CommandInfoNotFoundException;
 import com.redhat.thermostat.common.cli.CommandInfoSource;
+import com.redhat.thermostat.common.cli.SimpleArguments;
 import com.redhat.thermostat.launcher.internal.HelpCommand;
 import com.redhat.thermostat.test.TestCommandContextFactory;
 import com.redhat.thermostat.test.cli.TestCommand;
@@ -240,22 +242,18 @@
     public void verifyHelpUnknownCmdPrintsSummaries() {
 
         CommandInfoSource infos = mock(CommandInfoSource.class);
-        Collection<CommandInfo> infoList = new ArrayList<CommandInfo>();
         
-        CommandInfo info1 = mock(CommandInfo.class);
-        when(info1.getName()).thenReturn("test1");
-        when(info1.getDescription()).thenReturn("test command 1");
-        infoList.add(info1);
-
-        when(infos.getCommandInfos()).thenReturn(infoList);
+        when(infos.getCommandInfo("test1")).thenThrow(new CommandInfoNotFoundException("test1"));
         mockCommandInfoSourceService(infos);
 
         HelpCommand cmd = new HelpCommand();
-        Arguments args = mock(Arguments.class);
+        SimpleArguments args = new SimpleArguments();
+        args.addNonOptionArgument("test1");
         cmd.run(ctxFactory.createContext(args));
 
-        String expected = "list of commands:\n\n"
-                        + " test1         test command 1\n";
+        String expected = "unknown command 'test1'\n"
+                        + "list of commands:\n\n";
+
         String actual = ctxFactory.getOutput();
         assertEquals(expected, actual);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,506 @@
+/*
+ * 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.launcher.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.isA;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.redhat.thermostat.bundles.OSGiRegistry;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.ActionNotifier;
+import com.redhat.thermostat.common.ApplicationInfo;
+import com.redhat.thermostat.common.Version;
+import com.redhat.thermostat.common.appctx.ApplicationContext;
+import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
+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.CommandInfo;
+import com.redhat.thermostat.common.cli.CommandInfoNotFoundException;
+import com.redhat.thermostat.common.cli.CommandInfoSource;
+import com.redhat.thermostat.common.config.ClientPreferences;
+import com.redhat.thermostat.common.locale.LocaleResources;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.tools.ApplicationState;
+import com.redhat.thermostat.common.tools.BasicCommand;
+import com.redhat.thermostat.launcher.DbService;
+import com.redhat.thermostat.launcher.DbServiceFactory;
+import com.redhat.thermostat.launcher.internal.HelpCommand;
+import com.redhat.thermostat.launcher.internal.LauncherImpl;
+import com.redhat.thermostat.launcher.internal.LauncherImpl.LoggingInitializer;
+import com.redhat.thermostat.test.StubBundleContext;
+import com.redhat.thermostat.test.TestCommandContextFactory;
+import com.redhat.thermostat.test.TestTimerFactory;
+import com.redhat.thermostat.test.cli.TestCommand;
+import com.redhat.thermostat.utils.keyring.Keyring;
+import com.redhat.thermostat.utils.keyring.KeyringProvider;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({FrameworkUtil.class, HelpCommand.class})
+public class LauncherTest {
+    
+    private static String defaultKeyringProvider;
+    private static final String name1 = "test1";
+    private static final String name2 = "test2";
+    private static final String name3 = "test3";
+      
+    @BeforeClass
+    public static void beforeClassSetUp() {
+        defaultKeyringProvider = System.getProperty(KeyringProvider.KEYRING_FACTORY_PROPERTY);
+    }
+    
+    @AfterClass
+    public static void afterClassTearDown() {
+        if (defaultKeyringProvider != null) {
+            System.setProperty(KeyringProvider.KEYRING_FACTORY_PROPERTY, defaultKeyringProvider);
+        }
+    }
+    
+    private static class TestCmd1 implements TestCommand.Handle {
+
+        @Override
+        public void run(CommandContext ctx) {
+            Arguments args = ctx.getArguments();
+            ctx.getConsole().getOutput().print(args.getArgument("arg1") + ", " + args.getArgument("arg2"));
+        }
+    }
+
+    private static class TestCmd2 implements TestCommand.Handle {
+        @Override
+        public void run(CommandContext ctx) {
+            Arguments args = ctx.getArguments();
+            ctx.getConsole().getOutput().print(args.getArgument("arg4") + ": " + args.getArgument("arg3"));
+        }
+    }
+
+    private TestCommandContextFactory  ctxFactory;
+    private StubBundleContext bundleContext;
+    private Bundle sysBundle;
+    private TestTimerFactory timerFactory;
+    private OSGiRegistry registry;
+    private LoggingInitializer loggingInitializer;
+    private DbServiceFactory dbServiceFactory;
+    private CommandInfoSource infos;
+    private ActionNotifier<ApplicationState> notifier;
+
+    private LauncherImpl launcher;
+
+    @Before
+    public void setUp() {
+
+        ApplicationContextUtil.resetApplicationContext();
+        timerFactory = new TestTimerFactory();
+        ApplicationContext.getInstance().setTimerFactory(timerFactory);
+        setupCommandContextFactory();
+
+        TestCommand cmd1 = new TestCommand(name1, new TestCmd1());
+        CommandInfo info1 = mock(CommandInfo.class);
+        when(info1.getName()).thenReturn(name1);
+        Options options1 = new Options();
+        Option opt1 = new Option(null, "arg1", true, null);
+        options1.addOption(opt1);
+        Option opt2 = new Option(null, "arg2", true, null);
+        options1.addOption(opt2);
+        cmd1.addOptions(opt1, opt2);
+        cmd1.setDescription("description 1");
+        when(info1.getDescription()).thenReturn("description 1");
+        when(info1.getOptions()).thenReturn(options1);
+        TestCommand cmd2 = new TestCommand("test2", new TestCmd2());
+        CommandInfo info2 = mock(CommandInfo.class);
+        when(info2.getName()).thenReturn(name2);
+        Options options2 = new Options();
+        Option opt3 = new Option(null, "arg3", true, null);
+        options2.addOption(opt3);
+        Option opt4 = new Option(null, "arg4", true, null);
+        options2.addOption(opt4);
+        cmd2.addOptions(opt3, opt4);
+        cmd2.setDescription("description 2");
+        when(info2.getDescription()).thenReturn("description 2");
+        when(info2.getOptions()).thenReturn(options2);
+
+        TestCommand cmd3 = new TestCommand(name3);
+        CommandInfo info3 = mock(CommandInfo.class);
+        when(info3.getName()).thenReturn(name3);
+        cmd3.setStorageRequired(true);
+        cmd3.setDescription("description 3");
+        when(info3.getDescription()).thenReturn("description 3");
+        when(info3.getOptions()).thenReturn(new Options());
+
+        BasicCommand basicCmd = mock(BasicCommand.class);
+        CommandInfo basicInfo = mock(CommandInfo.class);
+        when(basicCmd.getName()).thenReturn("basic");
+        when(basicInfo.getName()).thenReturn("basic");
+        when(basicCmd.getDescription()).thenReturn("nothing that means anything");
+        when(basicInfo.getDescription()).thenReturn("nothing that means anything");
+        when(basicCmd.isStorageRequired()).thenReturn(false);
+        Options options = new Options();
+        when(basicCmd.getOptions()).thenReturn(options);
+        when(basicInfo.getOptions()).thenReturn(options);
+        notifier = mock(ActionNotifier.class);
+        when(basicCmd.getNotifier()).thenReturn(notifier);
+        CommandInfo helpCommandInfo = mock(CommandInfo.class);
+        when(helpCommandInfo.getName()).thenReturn("help");
+        when(helpCommandInfo.getDescription()).thenReturn("print help information");
+        when(helpCommandInfo.getDependencyResourceNames()).thenReturn(new ArrayList<String>());
+        when(helpCommandInfo.getOptions()).thenReturn(new Options());
+        when(helpCommandInfo.getUsage()).thenReturn("thermostat help");
+
+        ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(new HelpCommand(), cmd1, cmd2, cmd3, basicCmd));
+
+        registry = mock(OSGiRegistry.class);
+
+        infos = mock(CommandInfoSource.class);
+        when(infos.getCommandInfo(name1)).thenReturn(info1);
+        when(infos.getCommandInfo(name2)).thenReturn(info2);
+        when(infos.getCommandInfo(name3)).thenReturn(info3);
+        when(infos.getCommandInfo("basic")).thenReturn(basicInfo);
+        when(infos.getCommandInfo("help")).thenReturn(helpCommandInfo);
+
+        Collection<CommandInfo> infoList = new ArrayList<CommandInfo>();
+        infoList.add(helpCommandInfo);
+        infoList.add(basicInfo);
+        infoList.add(info1);
+        infoList.add(info2);
+        infoList.add(info3);
+        when(infos.getCommandInfos()).thenReturn(infoList);
+
+        PowerMockito.mockStatic(FrameworkUtil.class);
+        Bundle bundle = mock(Bundle.class);
+        BundleContext bCtx = mock(BundleContext.class);
+        when(bundle.getBundleContext()).thenReturn(bCtx);
+        ServiceReference infosRef = mock(ServiceReference.class);
+        when(bCtx.getServiceReference(CommandInfoSource.class)).thenReturn(infosRef);
+        when(bCtx.getService(infosRef)).thenReturn(infos);
+        when(FrameworkUtil.getBundle(isA(HelpCommand.class.getClass()))).thenReturn(bundle);
+
+        loggingInitializer = mock(LoggingInitializer.class);
+        dbServiceFactory = mock(DbServiceFactory.class);
+
+        launcher = new LauncherImpl(bundleContext, ctxFactory, registry, loggingInitializer, dbServiceFactory);
+
+        Keyring keyring = mock(Keyring.class);
+        launcher.setPreferences(new ClientPreferences(keyring));
+    }
+
+    private void setupCommandContextFactory() {
+        sysBundle = mock(Bundle.class);
+        bundleContext = new StubBundleContext();
+        bundleContext.setBundle(0, sysBundle);
+        ctxFactory = new TestCommandContextFactory(bundleContext);
+    }
+
+
+    @After
+    public void tearDown() {
+        ctxFactory = null;
+        ApplicationContextUtil.resetApplicationContext();
+    }
+
+    @Test
+    public void testMain() {
+        runAndVerifyCommand(new String[] {name1, "--arg1", "Hello", "--arg2", "World"}, "Hello, World");
+
+        ctxFactory.reset();
+
+        runAndVerifyCommand(new String[] {"test2", "--arg3", "Hello", "--arg4", "World"}, "World: Hello");
+    }
+
+    @Test
+    public void testMainNoArgs() {
+        String expected = "list of commands:\n\n"
+                        + " help          print help information\n"
+                        + " basic         nothing that means anything\n"
+                        + " test1         description 1\n"
+                        + " test2         description 2\n"
+                        + " test3         description 3\n";
+        runAndVerifyCommand(new String[0], expected);
+    }
+
+    @Test
+    public void verifySetLogLevel() {
+        runAndVerifyCommand(new String[] {name1, "--logLevel", "WARNING", "--arg1", "Hello", "--arg2", "World"}, "Hello, World");
+        Logger globalLogger = Logger.getLogger("com.redhat.thermostat");
+        assertEquals(Level.WARNING, globalLogger.getLevel());
+    }
+
+    @Test
+    public void testMainBadCommand1() {
+        when(infos.getCommandInfo("--help")).thenThrow(new CommandInfoNotFoundException("--help"));
+
+        String expected = "unknown command '--help'\n"
+            + "list of commands:\n\n"
+            + " help          print help information\n"
+            + " basic         nothing that means anything\n"
+            + " test1         description 1\n"
+            + " test2         description 2\n"
+            + " test3         description 3\n";
+        runAndVerifyCommand(new String[] {"--help"}, expected);
+    }
+
+    @Test
+    public void testMainBadCommand2() {
+        when(infos.getCommandInfo("-help")).thenThrow(new CommandInfoNotFoundException("-help"));
+
+        String expected = "unknown command '-help'\n"
+            + "list of commands:\n\n"
+            + " help          print help information\n"
+            + " basic         nothing that means anything\n"
+            + " test1         description 1\n"
+            + " test2         description 2\n"
+            + " test3         description 3\n";
+        runAndVerifyCommand(new String[] {"-help"}, expected);
+    }
+
+    @Test
+    public void testMainBadCommand3() {
+        when(infos.getCommandInfo("foobarbaz")).thenThrow(new CommandInfoNotFoundException("foobarbaz"));
+
+        String expected = "unknown command 'foobarbaz'\n"
+            + "list of commands:\n\n"
+            + " help          print help information\n"
+            + " basic         nothing that means anything\n"
+            + " test1         description 1\n"
+            + " test2         description 2\n"
+            + " test3         description 3\n";
+        runAndVerifyCommand(new String[] {"foobarbaz"}, expected);
+    }
+
+    @Test
+    public void testMainBadCommand4() {
+        when(infos.getCommandInfo("foo")).thenThrow(new CommandInfoNotFoundException("foo"));
+
+        String expected = "unknown command 'foo'\n"
+            + "list of commands:\n\n"
+            + " help          print help information\n"
+            + " basic         nothing that means anything\n"
+            + " test1         description 1\n"
+            + " test2         description 2\n"
+            + " test3         description 3\n";
+        runAndVerifyCommand(new String[] {"foo",  "--bar", "baz"}, expected);
+    }
+
+    @Test
+    public void testCommandInfoNotFound() throws CommandInfoNotFoundException, BundleException, IOException {
+        when(infos.getCommandInfo("foo")).thenThrow(new CommandInfoNotFoundException("foo"));
+        doThrow(new CommandInfoNotFoundException("foo")).when(registry).addBundlesFor("foo");
+
+        String expected = "unknown command 'foo'\n"
+                + "list of commands:\n\n"
+                + " help          print help information\n"
+                + " basic         nothing that means anything\n"
+                + " test1         description 1\n"
+                + " test2         description 2\n"
+                + " test3         description 3\n";
+            runAndVerifyCommand(new String[] {"foo"}, expected);
+    }
+
+    @Test
+    public void testMainExceptionInCommand() {
+        TestCommand errorCmd = new TestCommand("error", new TestCommand.Handle() {
+
+            @Override
+            public void run(CommandContext ctx) throws CommandException {
+                throw new CommandException("test error");
+            }
+
+        });
+        ctxFactory.getCommandRegistry().registerCommands(Arrays.asList(errorCmd));
+
+        launcher.setArgs(new String[] { "error" });
+        launcher.run();
+        assertEquals("test error\n", ctxFactory.getError());
+
+    }
+
+    private void runAndVerifyCommand(String[] args, String expected) {
+        launcher.setArgs(args);
+        launcher.run();
+        assertEquals(expected, ctxFactory.getOutput());
+        assertTrue(timerFactory.isShutdown());
+    }
+
+    @Test
+    public void verifyStorageCommandSetsUpDAOFactory() {
+        String dbUrl = "mongo://fluff:12345";
+        DbService dbService = mock(DbService.class);
+        when(dbServiceFactory.createDbService(null, null, dbUrl)).thenReturn(dbService);
+        
+        launcher.setArgs(new String[] { "test3" , "--dbUrl", dbUrl });
+        launcher.run();
+
+        verify(dbService).connect();
+        verify(dbService).setServiceRegistration(any(ServiceRegistration.class));
+    }
+
+    @Test
+    public void verifyStorageCommandSetsUpDAOFactoryWithAuth() {
+        String dbUrl = "mongo://fluff:12345";
+        String testUser = "testUser";
+        String testPasswd = "testPassword";
+        DbService dbService = mock(DbService.class);
+        when(dbServiceFactory.createDbService(testUser, testPasswd, dbUrl)).thenReturn(dbService);
+        
+        launcher.setArgs(new String[] { "test3" , "--dbUrl", dbUrl, "--username", testUser, "--password", testPasswd });
+        launcher.run();
+        verify(dbService).connect();
+        verify(dbService).setServiceRegistration(any(ServiceRegistration.class));
+    }
+
+    @Test
+    public void verifyPrefsAreUsed() {
+        ClientPreferences prefs = mock(ClientPreferences.class);
+        String dbUrl = "mongo://fluff:12345";
+        when(prefs.getConnectionUrl()).thenReturn(dbUrl);
+
+        DbService dbService = mock(DbService.class);
+        // this makes sure that dbUrl is indeed retrieved from preferences
+        when(dbServiceFactory.createDbService(null, null, dbUrl)).thenReturn(dbService);
+        launcher.setPreferences(prefs);
+        launcher.setArgs(new String[] { "test3" });
+        launcher.run();
+        verify(dbService).connect();
+        verify(dbService).setServiceRegistration(any(ServiceRegistration.class));
+    }
+
+    @Ignore("needs a storage-requiring service")
+    @Test
+    public void verifyDbServiceIsRegistered() {
+        DbService dbService = mock(DbService.class);
+        when(dbServiceFactory.createDbService(anyString(), anyString(), anyString())).thenReturn(dbService);
+
+        launcher.setArgs(new String[] { "ignore" });
+        launcher.run();
+
+        assertTrue(bundleContext.isServiceRegistered(DbService.class.getName(), dbService.getClass()));
+    }
+
+    @Test
+    public void verifyVersionInfoQuery() {
+        int major = 0;
+        int minor = 3;
+        int micro = 0;
+        
+        ApplicationInfo appInfo = new ApplicationInfo();
+        Translate<LocaleResources> t = LocaleResources.createLocalizer();
+        String format = MessageFormat.format(
+                t.localize(LocaleResources.APPLICATION_VERSION_INFO),
+                appInfo.getName())
+                + " " + Version.VERSION_NUMBER_FORMAT;
+        
+        String expectedVersionInfo = String.format(format,
+                major, minor, micro) + "\n";
+        
+        String qualifier = "201207241700";
+
+        org.osgi.framework.Version ver = org.osgi.framework.Version
+                .parseVersion(String.format(Version.VERSION_NUMBER_FORMAT,
+                        major, minor, micro) + "." + qualifier);
+        when(sysBundle.getVersion()).thenReturn(ver);
+        
+        PowerMockito.mockStatic(FrameworkUtil.class);
+        when(FrameworkUtil.getBundle(Version.class)).thenReturn(sysBundle);
+        
+        launcher.setArgs(new String[] {Version.VERSION_OPTION});
+        launcher.run();
+
+        assertEquals(expectedVersionInfo, ctxFactory.getOutput());
+        assertTrue(timerFactory.isShutdown());
+    }
+
+    @Test
+    public void verifyListenersAdded() {
+        ActionListener<ApplicationState> listener = mock(ActionListener.class);
+        Collection<ActionListener<ApplicationState>> listeners = new ArrayList<>();
+        listeners.add(listener);
+        String[] args = new String[] {"basic"};
+
+        launcher.setArgs(args);
+        launcher.run(listeners);
+        verify(notifier).addActionListener(listener);
+    }
+
+    @Test
+    public void verifyLoggingIsInitialized() {
+        launcher.setArgs(new String[] { "test1" });
+        launcher.run();
+
+        verify(loggingInitializer).initialize();
+    }
+
+    @Test
+    public void verifyShutdown() throws BundleException {
+        launcher.setArgs(new String[] { "test1" });
+        launcher.run();
+
+        verify(sysBundle).stop();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LocaleResourcesTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -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.launcher.internal;
+
+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()));
+        }
+    }
+}
\ No newline at end of file
--- a/main/src/main/java/com/redhat/thermostat/main/Thermostat.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/main/src/main/java/com/redhat/thermostat/main/Thermostat.java	Fri Oct 26 15:32:56 2012 +0200
@@ -75,7 +75,6 @@
 
     @Override
     public void run() {
-        System.out.println("Launching...");
         try {
             launch();
         } catch (IOException | NoSuchMethodException | InterruptedException |
--- a/main/src/main/resources/com/redhat/thermostat/main/impl/bootstrapbundles.properties	Fri Oct 26 13:13:42 2012 +0200
+++ b/main/src/main/resources/com/redhat/thermostat/main/impl/bootstrapbundles.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -3,4 +3,11 @@
         thermostat-bundles-${project.version}.jar, \
         thermostat-tools-${project.version}.jar, \
         thermostat-launcher-${project.version}.jar, \
-        thermostat-main-${project.version}.jar
+        thermostat-main-${project.version}.jar, \
+        jline2.jar, \
+        commons-cli.jar, \
+        commons-beanutils.jar, \
+        commons-collections.jar, \
+        commons-logging.jar, \
+        lucene.jar, \
+        mongo.jar
--- a/pom.xml	Fri Oct 26 13:13:42 2012 +0200
+++ b/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -73,8 +73,10 @@
     <commons-beanutils.version>1.8.3</commons-beanutils.version>
     <commons-cli.version>1.2</commons-cli.version>
     <commons-io.version>2.4</commons-io.version>
-    <jline.version>2.5</jline.version>
-    <lucene.version>3.6.0</lucene.version>
+    <commons-collections.version>3.2.1</commons-collections.version>
+    <commons-logging.version>1.1.1</commons-logging.version>
+    <jline.version>2.9</jline.version>
+    <lucene.version>3.6.0_1</lucene.version>
     <!--
          felix 4.0 is compliant with osgi 4.3
          for osgi clients, 4.3 is backwards compatible with 4.2
@@ -96,6 +98,16 @@
         <enabled>false</enabled>
       </snapshots>
     </repository>
+    <repository>
+      <id>com.springsource.repository.bundles.release</id>
+      <name>SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases</name>
+      <url>http://repository.springsource.com/maven/bundles/release</url>
+    </repository>
+    <repository>
+      <id>com.springsource.repository.bundles.external</id>
+      <name>SpringSource Enterprise Bundle Repository - External Bundle Releases</name>
+      <url>http://repository.springsource.com/maven/bundles/external</url>
+    </repository> 
   </repositories>
 
   <modules>
@@ -283,18 +295,29 @@
         <version>${commons-beanutils.version}</version>
       </dependency>
       <dependency>
+        <groupId>commons-collections</groupId>
+        <artifactId>commons-collections</artifactId>
+        <version>${commons-collections.version}</version>
+      </dependency>
+      <dependency>
+        <!-- comes from spring repo -->
+        <groupId>org.apache.commons</groupId>
+        <artifactId>com.springsource.org.apache.commons.logging</artifactId>
+        <version>${commons-logging.version}</version>
+      </dependency>
+      <dependency>
         <groupId>commons-cli</groupId>
         <artifactId>commons-cli</artifactId>
         <version>${commons-cli.version}</version>
       </dependency>
       <dependency>
-        <groupId>org.sonatype.jline</groupId>
+        <groupId>jline</groupId>
         <artifactId>jline</artifactId>
         <version>${jline.version}</version>
       </dependency>
     <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-core</artifactId>
+      <groupId>org.apache.servicemix.bundles</groupId>
+      <artifactId>org.apache.servicemix.bundles.lucene</artifactId>
       <version>${lucene.version}</version>
     </dependency>
 
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/osgi/SystemBackendActivator.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/osgi/SystemBackendActivator.java	Fri Oct 26 15:32:56 2012 +0200
@@ -54,7 +54,6 @@
     @SuppressWarnings("unchecked")
     @Override
     public void start(BundleContext context) throws Exception {
-        System.err.println("loading SystemBackendActivator");
         
         backend = new SystemBackend();
         
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/chart/ChartColors.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/chart/ChartColors.java	Fri Oct 26 15:32:56 2012 +0200
@@ -38,7 +38,7 @@
 
 import java.awt.Color;
 
-import com.redhat.thermostat.swing.Palette;
+import com.redhat.thermostat.client.ui.Palette;
 
 public class ChartColors {
     
--- a/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/locale/LocaleResources.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/thread/client-common/src/main/java/com/redhat/thermostat/thread/client/common/locale/LocaleResources.java	Fri Oct 26 15:32:56 2012 +0200
@@ -53,6 +53,7 @@
     
     START_RECORDING,
     STOP_RECORDING,
+    THREAD_MONITOR_SWITCH,
     
     VM_CAPABILITIES,
     TABLE,
--- a/thread/client-common/src/main/resources/com/redhat/thermostat/thread/client/common/locale/strings.properties	Fri Oct 26 13:13:42 2012 +0200
+++ b/thread/client-common/src/main/resources/com/redhat/thermostat/thread/client/common/locale/strings.properties	Fri Oct 26 15:32:56 2012 +0200
@@ -13,6 +13,8 @@
     
 START_RECORDING = Start Recording
 STOP_RECORDING = Stop Recording
+THREAD_MONITOR_SWITCH = Monitor Thread
+
 VM_CAPABILITIES = VM Capabilities
 TABLE = Table
 DETAILS = Details
--- a/thread/client-swing/pom.xml	Fri Oct 26 13:13:42 2012 +0200
+++ b/thread/client-swing/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -90,6 +90,12 @@
       <scope>test</scope>
     </dependency>
     
+    <dependency>
+        <groupId>com.redhat.thermostat</groupId>
+        <artifactId>thermostat-client-swing</artifactId>
+        <version>${project.version}</version>
+    </dependency>
+
   </dependencies>
 
   <build>
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadDetailsView.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadDetailsView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -43,9 +43,9 @@
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 
-import com.redhat.thermostat.client.ui.SwingComponent;
+import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.client.swing.components.ChartPanel;
 import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.swing.ChartPanel;
 import com.redhat.thermostat.thread.client.common.ThreadDetailsView;
 import com.redhat.thermostat.thread.client.common.ThreadTableBean;
 import com.redhat.thermostat.thread.client.common.chart.ThreadDeatailsPieChart;
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadTableView.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadTableView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -49,9 +49,9 @@
 import javax.swing.event.TableModelListener;
 import javax.swing.table.DefaultTableModel;
 
+import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.client.swing.components.ThermostatTable;
 import com.redhat.thermostat.client.ui.ComponentVisibleListener;
-import com.redhat.thermostat.client.ui.SwingComponent;
-import com.redhat.thermostat.swing.ThermostatTable;
 import com.redhat.thermostat.thread.client.common.locale.LocaleResources;
 import com.redhat.thermostat.common.locale.Translate;
 import com.redhat.thermostat.thread.client.common.ThreadTableBean;
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadTimelineChart.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadTimelineChart.java	Fri Oct 26 15:32:56 2012 +0200
@@ -57,11 +57,11 @@
 import javax.swing.JPanel;
 import javax.swing.SwingUtilities;
 
-import com.redhat.thermostat.swing.GradientRoundBorder;
-import com.redhat.thermostat.swing.GraphicsUtils;
-import com.redhat.thermostat.swing.Palette;
-import com.redhat.thermostat.swing.models.LongRange;
-import com.redhat.thermostat.swing.models.LongRangeNormalizer;
+import com.redhat.thermostat.client.swing.components.GradientRoundBorder;
+import com.redhat.thermostat.client.swing.components.GraphicsUtils;
+import com.redhat.thermostat.client.swing.components.models.LongRange;
+import com.redhat.thermostat.client.swing.components.models.LongRangeNormalizer;
+import com.redhat.thermostat.client.ui.Palette;
 import com.redhat.thermostat.thread.client.common.ThreadTimelineBean;
 import com.redhat.thermostat.thread.client.common.chart.ChartColors;
 
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadTimelineView.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadTimelineView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -56,8 +56,8 @@
 import javax.swing.SwingUtilities;
 import javax.swing.SwingWorker;
 
+import com.redhat.thermostat.client.swing.SwingComponent;
 import com.redhat.thermostat.client.ui.ComponentVisibleListener;
-import com.redhat.thermostat.client.ui.SwingComponent;
 import com.redhat.thermostat.thread.client.common.ThreadTimelineBean;
 import com.redhat.thermostat.thread.client.common.ThreadTimelineView;
 import com.redhat.thermostat.thread.model.ThreadInfoData;
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadView.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -50,10 +50,10 @@
 import javax.swing.SwingWorker;
 
 import com.redhat.thermostat.client.osgi.service.ApplicationService;
+import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.client.swing.components.ChartPanel;
 import com.redhat.thermostat.client.ui.ComponentVisibleListener;
-import com.redhat.thermostat.client.ui.SwingComponent;
 import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.swing.ChartPanel;
 import com.redhat.thermostat.thread.client.common.ThreadTableBean;
 import com.redhat.thermostat.thread.client.common.ThreadTableView;
 import com.redhat.thermostat.thread.client.common.ThreadTimelineView;
@@ -111,6 +111,7 @@
         
         timelinePanel = new ThreadAliveDaemonTimelinePanel();
         panel.getToggleButton().setToolTipText(t.localize(LocaleResources.START_RECORDING));
+        panel.getToggleButton().setText(t.localize(LocaleResources.THREAD_MONITOR_SWITCH));
         panel.getToggleButton().addItemListener(new ItemListener()
         {
             @Override
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingVMThreadCapabilitiesView.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingVMThreadCapabilitiesView.java	Fri Oct 26 15:32:56 2012 +0200
@@ -41,8 +41,8 @@
 import javax.swing.SwingUtilities;
 import javax.swing.SwingWorker;
 
+import com.redhat.thermostat.client.swing.SwingComponent;
 import com.redhat.thermostat.client.ui.ComponentVisibleListener;
-import com.redhat.thermostat.client.ui.SwingComponent;
 import com.redhat.thermostat.thread.client.common.VMThreadCapabilitiesView;
 import com.redhat.thermostat.thread.model.VMThreadCapabilities;
 
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadMainPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadMainPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -43,9 +43,9 @@
 import javax.swing.JPanel;
 import javax.swing.JSplitPane;
 
+import com.redhat.thermostat.client.swing.components.ActionToggleButton;
+import com.redhat.thermostat.client.swing.components.HeaderPanel;
 import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.swing.ActionToggleButton;
-import com.redhat.thermostat.swing.HeaderPanel;
 import com.redhat.thermostat.thread.client.common.IconResources;
 import com.redhat.thermostat.thread.client.common.locale.LocaleResources;
 
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadTimelineLegendPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/ThreadTimelineLegendPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -50,7 +50,7 @@
 import javax.swing.SwingConstants;
 import javax.swing.SwingUtilities;
 
-import com.redhat.thermostat.swing.GraphicsUtils;
+import com.redhat.thermostat.client.swing.components.GraphicsUtils;
 import com.redhat.thermostat.thread.client.common.chart.ChartColors;
 
 @SuppressWarnings("serial")
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/VMCapsSummaryPanel.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/VMCapsSummaryPanel.java	Fri Oct 26 15:32:56 2012 +0200
@@ -42,7 +42,7 @@
 import javax.swing.JList;
 import javax.swing.JPanel;
 
-import com.redhat.thermostat.swing.models.NullSelectionModel;
+import com.redhat.thermostat.client.swing.components.models.NullSelectionModel;
 
 @SuppressWarnings("serial")
 class VMCapsSummaryPanel extends JPanel {
--- a/thread/client-swing/src/test/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadViewTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/thread/client-swing/src/test/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadViewTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -57,7 +57,6 @@
 import org.fest.swing.edt.GuiActionRunner;
 import org.fest.swing.edt.GuiTask;
 import org.fest.swing.fixture.FrameFixture;
-import org.fest.swing.fixture.JLabelFixture;
 import org.fest.swing.fixture.JToggleButtonFixture;
 import org.junit.After;
 import org.junit.AfterClass;
--- a/tools/pom.xml	Fri Oct 26 13:13:42 2012 +0200
+++ b/tools/pom.xml	Fri Oct 26 15:32:56 2012 +0200
@@ -72,7 +72,7 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>org.sonatype.jline</groupId>
+      <groupId>jline</groupId>
       <artifactId>jline</artifactId>
     </dependency>
     <dependency>
--- a/tools/src/main/java/com/redhat/thermostat/tools/cli/ConnectCommand.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/tools/src/main/java/com/redhat/thermostat/tools/cli/ConnectCommand.java	Fri Oct 26 15:32:56 2012 +0200
@@ -66,7 +66,16 @@
     private static final String NAME = "connect";
     
     private ClientPreferences prefs;
-    
+    private DbServiceFactory dbServiceFactory;
+
+    public ConnectCommand() {
+        this(new DbServiceFactory());
+    }
+
+    ConnectCommand(DbServiceFactory dbServiceFactory) {
+        this.dbServiceFactory = dbServiceFactory;
+    }
+
     @SuppressWarnings("rawtypes")
     @Override
     public void run(CommandContext ctx) throws CommandException {
@@ -84,7 +93,7 @@
         }
         String username = ctx.getArguments().getArgument(CommonCommandOptions.USERNAME_ARG);
         String password = ctx.getArguments().getArgument(CommonCommandOptions.PASSWORD_ARG);
-        service = DbServiceFactory.createDbService(username, password, dbUrl);
+        service = dbServiceFactory.createDbService(username, password, dbUrl);
         try {
             service.connect();
         } catch (ConnectionException ex) {
--- a/tools/src/main/java/com/redhat/thermostat/tools/cli/ShellCommand.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/tools/src/main/java/com/redhat/thermostat/tools/cli/ShellCommand.java	Fri Oct 26 15:32:56 2012 +0200
@@ -130,7 +130,7 @@
     }
 
     private void shellMainLoop(CommandContext ctx, History history, Terminal term) throws IOException, CommandException {
-        ConsoleReader reader = new ConsoleReader(ctx.getConsole().getInput(), new OutputStreamWriter(ctx.getConsole().getOutput()), term);
+        ConsoleReader reader = new ConsoleReader(ctx.getConsole().getInput(), ctx.getConsole().getOutput(), term);
         if (history != null) {
             reader.setHistory(history);
         }
--- a/tools/src/test/java/com/redhat/thermostat/tools/cli/ConnectCommandTest.java	Fri Oct 26 13:13:42 2012 +0200
+++ b/tools/src/test/java/com/redhat/thermostat/tools/cli/ConnectCommandTest.java	Fri Oct 26 15:32:56 2012 +0200
@@ -81,13 +81,16 @@
     private ConnectCommand cmd;
     private TestCommandContextFactory cmdCtxFactory;
     private BundleContext bundleContext;
+    private DbServiceFactory dbServiceFactory;
 
     @Before
     public void setUp() {
         ApplicationContextUtil.resetApplicationContext();
         setupCommandContextFactory();
 
-        cmd = new ConnectCommand();
+        dbServiceFactory = mock(DbServiceFactory.class);
+
+        cmd = new ConnectCommand(dbServiceFactory);
 
     }
 
@@ -130,11 +133,11 @@
         when(utils.getServiceAllowNull(DbService.class)).thenReturn(null);
 
         DbService dbService = mock(DbService.class);
-        PowerMockito.mockStatic(DbServiceFactory.class);
+
         String username = "testuser";
         String password = "testpassword";
         String dbUrl = "mongodb://10.23.122.1:12578";
-        when(DbServiceFactory.createDbService(eq(username), eq(password), eq(dbUrl))).thenReturn(dbService);
+        when(dbServiceFactory.createDbService(eq(username), eq(password), eq(dbUrl))).thenReturn(dbService);
         SimpleArguments args = new SimpleArguments();
         args.addArgument("dbUrl", dbUrl);
         args.addArgument("username", username);
--- a/web/client/pom.xml~	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +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-web</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
-  </parent>
-
-  <artifactId>thermostat-web-server</artifactId>
-  <packaging>war</packaging>
-
-  <name>Thermostat Web Server</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.eclipse.jetty</groupId>
-      <artifactId>jetty-server</artifactId>
-      <version>8.1.5.v20120716</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-webapp</artifactId>
-      <version>8.1.5.v20120716</version>
-      <scope>test</scope>
-    </dependency>
-
-
-    <dependency>
-      <groupId>javax.servlet</groupId>
-      <artifactId>servlet-api</artifactId>
-      <version>2.5</version>
-    </dependency>
-
-    <dependency>
-      <groupId>com.google.code.gson</groupId>
-      <artifactId>gson</artifactId>
-      <version>2.2.2</version>
-    </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/web/client/src/main/resources/META-INF/p2.inf	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,7 @@
+# Instructs Eclipse update manager to auto-start this bundle
+instructions.configure = \
+org.eclipse.equinox.p2.touchpoint.eclipse.setStartLevel(startLevel: 4); \
+org.eclipse.equinox.p2.touchpoint.eclipse.markStarted(started: true);
+instructions.unconfigure = \
+org.eclipse.equinox.p2.touchpoint.eclipse.setStartLevel(startLevel: -1); \
+org.eclipse.equinox.p2.touchpoint.eclipse.markStarted(started: false);
--- a/web/common/pom.xml~	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +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-web</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
-  </parent>
-
-  <artifactId>thermostat-web-client</artifactId>
-  <packaging>war</packaging>
-
-  <name>Thermostat Web Client</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.eclipse.jetty</groupId>
-      <artifactId>jetty-server</artifactId>
-      <version>8.1.5.v20120716</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-webapp</artifactId>
-      <version>8.1.5.v20120716</version>
-      <scope>test</scope>
-    </dependency>
-
-
-    <dependency>
-      <groupId>com.google.code.gson</groupId>
-      <artifactId>gson</artifactId>
-      <version>2.2.2</version>
-    </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/web/common/src/main/resources/META-INF/p2.inf	Fri Oct 26 15:32:56 2012 +0200
@@ -0,0 +1,7 @@
+# Instructs Eclipse update manager to auto-start this bundle
+instructions.configure = \
+org.eclipse.equinox.p2.touchpoint.eclipse.setStartLevel(startLevel: 4); \
+org.eclipse.equinox.p2.touchpoint.eclipse.markStarted(started: true);
+instructions.unconfigure = \
+org.eclipse.equinox.p2.touchpoint.eclipse.setStartLevel(startLevel: -1); \
+org.eclipse.equinox.p2.touchpoint.eclipse.markStarted(started: false);
--- a/web/server/pom.xml~	Fri Oct 26 13:13:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +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</artifactId>
-    <version>0.4.0-SNAPSHOT</version>
-  </parent>
-
-  <artifactId>thermostat-web</artifactId>
-  <packaging>war</packaging>
-
-  <name>Thermostat Web</name>
-
-  <repositories>
-	<repository>
-      <id>JBoss repository</id>
-      <url>https://repository.jboss.org/nexus/content/groups/public-jboss/</url>
-    </repository>
-  </repositories>
-
-  <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.eclipse.jetty</groupId>
-      <artifactId>jetty-server</artifactId>
-      <version>8.1.5.v20120716</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-webapp</artifactId>
-      <version>8.1.5.v20120716</version>
-      <scope>test</scope>
-    </dependency>
-
-
-    <dependency>
-      <groupId>javax.servlet</groupId>
-      <artifactId>servlet-api</artifactId>
-      <version>2.5</version>
-    </dependency>
-
-    <dependency>
-      <groupId>com.google.code.gson</groupId>
-      <artifactId>gson</artifactId>
-      <version>2.2.2</version>
-    </dependency>
-
-    <dependency>
-      <groupId>com.redhat.thermostat.</groupId>
-      <artifactId>thermostat-common-core</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-
-  </dependencies>
-
-</project>