changeset 800:0f3c06ce2d00

Move Host CPU to its own bundle This commit creates a new bundle for the Host CPU view and controller. This bundle also registers a HostCpuService which dynamically adds the Host CPU controller to the GUI. Since the HostCpuPanel Swing view relied on an internal class WrapLayout, the agreed upon solution (on IRC) is to move WrapLayout to a recreated swing-components bundle under an experimental package name. Reviewed-by: jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-November/004234.html
author Elliott Baron <ebaron@redhat.com>
date Tue, 27 Nov 2012 14:47:49 -0500
parents 15afbd5a66c4
children 18a8839b9638
files client/core/src/main/java/com/redhat/thermostat/client/core/views/HostCpuView.java client/core/src/main/java/com/redhat/thermostat/client/core/views/HostCpuViewProvider.java client/core/src/main/java/com/redhat/thermostat/client/locale/LocaleResources.java client/core/src/main/java/com/redhat/thermostat/client/ui/HostCpuController.java client/core/src/main/java/com/redhat/thermostat/client/ui/HostInformationController.java client/core/src/main/java/com/redhat/thermostat/client/ui/UiFacadeFactory.java client/core/src/main/resources/com/redhat/thermostat/client/locale/strings.properties client/core/src/test/java/com/redhat/thermostat/client/ui/HostCpuControllerTest.java client/pom.xml client/swing-components/pom.xml client/swing-components/src/main/java/com/redhat/thermostat/swing/components/experimental/WrapLayout.java client/swing/pom.xml client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/Main.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/UiFacadeFactoryImpl.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/WrapLayout.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/ThermostatActivator.java client/swing/src/main/java/com/redhat/thermostat/client/swing/views/HostCpuPanel.java client/swing/src/main/java/com/redhat/thermostat/client/swing/views/HostMemoryPanel.java client/swing/src/main/java/com/redhat/thermostat/client/swing/views/SwingHostCpuViewProvider.java client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/osgi/ThermostatActivatorTest.java distribution/config/commands/gui.properties distribution/pom.xml eclipse/com.redhat.thermostat.client.feature/feature.xml eclipse/com.redhat.thermostat.client.feature/pom.xml eclipse/com.redhat.thermostat.eclipse.chart.common/META-INF/MANIFEST.MF eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/Activator.java eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/HostCpuViewPart.java eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/SWTHostCpuView.java eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/SWTHostCpuViewProvider.java eclipse/com.redhat.thermostat.eclipse.test.ui/META-INF/MANIFEST.MF eclipse/com.redhat.thermostat.eclipse.test/META-INF/MANIFEST.MF eclipse/com.redhat.thermostat.eclipse.test/src/com/redhat/thermostat/eclipse/test/views/HostCpuViewPartTest.java host-cpu/client-core/pom.xml host-cpu/client-core/src/main/java/com/redhat/thermostat/host/cpu/client/core/HostCpuController.java host-cpu/client-core/src/main/java/com/redhat/thermostat/host/cpu/client/core/HostCpuService.java host-cpu/client-core/src/main/java/com/redhat/thermostat/host/cpu/client/core/HostCpuView.java host-cpu/client-core/src/main/java/com/redhat/thermostat/host/cpu/client/core/HostCpuViewProvider.java host-cpu/client-core/src/main/java/com/redhat/thermostat/host/cpu/client/locale/LocaleResources.java host-cpu/client-core/src/main/resources/com/redhat/thermostat/host/cpu/client/locale/strings.properties host-cpu/client-core/src/test/java/com/redhat/thermostat/host/cpu/client/core/HostCpuControllerTest.java host-cpu/client-swing/pom.xml host-cpu/client-swing/src/main/java/com/redhat/thermostat/host/cpu/client/swing/Activator.java host-cpu/client-swing/src/main/java/com/redhat/thermostat/host/cpu/client/swing/HostCpuPanel.java host-cpu/client-swing/src/main/java/com/redhat/thermostat/host/cpu/client/swing/SwingHostCpuViewProvider.java host-cpu/client-swing/src/test/java/com/redhat/thermostat/host/cpu/client/swing/ActivatorTest.java host-cpu/pom.xml pom.xml
diffstat 47 files changed, 1691 insertions(+), 1054 deletions(-) [+]
line wrap: on
line diff
--- a/client/core/src/main/java/com/redhat/thermostat/client/core/views/HostCpuView.java	Tue Nov 27 14:45:51 2012 -0500
+++ /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.core.views;
-
-import java.util.List;
-
-import com.redhat.thermostat.storage.model.DiscreteTimeData;
-
-public abstract class HostCpuView extends BasicView implements UIComponent {
-
-    public abstract void setCpuCount(String count);
-
-    public abstract void setCpuModel(String model);
-
-    public abstract void clearCpuUsageData();
-
-    public abstract void addCpuUsageChart(int cpuIndex, String humanReadableName);
-
-    public abstract void addCpuUsageData(int cpuIndex, List<DiscreteTimeData<Double>> data);
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/core/views/HostCpuViewProvider.java	Tue Nov 27 14:45:51 2012 -0500
+++ /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.client.core.views;
-
-public interface HostCpuViewProvider extends ViewProvider {
-
-    @Override
-    HostCpuView createView();
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/locale/LocaleResources.java	Tue Nov 27 14:45:51 2012 -0500
+++ b/client/core/src/main/java/com/redhat/thermostat/client/locale/LocaleResources.java	Tue Nov 27 14:47:49 2012 -0500
@@ -109,13 +109,8 @@
     HOME_PANEL_NO_ISSUES,
 
     HOST_INFO_TAB_MEMORY,
-    HOST_INFO_TAB_CPU,
     HOST_INFO_TAB_IO,
 
-    HOST_CPU_SECTION_OVERVIEW,
-    HOST_CPU_ID,
-    HOST_CPU_USAGE_CHART_TIME_LABEL,
-    HOST_CPU_USAGE_CHART_VALUE_LABEL,
     HOST_MEMORY_SECTION_OVERVIEW,
     HOST_MEMORY_CHART_TITLE,
     HOST_MEMORY_CHART_TIME_LABEL,
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/HostCpuController.java	Tue Nov 27 14:45:51 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,161 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not 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 java.util.concurrent.TimeUnit;
-
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.core.views.HostCpuView;
-import com.redhat.thermostat.client.core.views.HostCpuViewProvider;
-import com.redhat.thermostat.client.core.views.BasicView.Action;
-import com.redhat.thermostat.client.core.views.UIComponent;
-import com.redhat.thermostat.client.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.CpuStatDAO;
-import com.redhat.thermostat.common.dao.HostInfoDAO;
-import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.storage.model.CpuStat;
-import com.redhat.thermostat.storage.model.DiscreteTimeData;
-import com.redhat.thermostat.storage.model.HostInfo;
-
-public class HostCpuController {
-
-    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
-
-    private final HostCpuView view;
-    private final Timer backgroundUpdateTimer;
-
-    private final HostInfoDAO hostInfoDAO;
-    private final CpuStatDAO cpuStatDAO;
-    private final HostRef ref;
-
-    private int chartsAdded = 0;
-    private long lastSeenTimeStamp = Long.MIN_VALUE;
-
-    public HostCpuController(HostInfoDAO hostInfoDao, CpuStatDAO cpuStatDAO, HostRef ref, HostCpuViewProvider provider) {
-        this.ref = ref;
-        view = provider.createView();
-        view.clearCpuUsageData();
-        this.hostInfoDAO = hostInfoDao;
-        this.cpuStatDAO = cpuStatDAO;
-
-        backgroundUpdateTimer = ApplicationContext.getInstance().getTimerFactory().createTimer();
-        backgroundUpdateTimer.setAction(new Runnable() {
-
-            @Override
-            public void run() {
-                updateView();
-            }
-
-        });
-        backgroundUpdateTimer.setInitialDelay(0);
-        backgroundUpdateTimer.setDelay(5);
-        backgroundUpdateTimer.setTimeUnit(TimeUnit.SECONDS);
-        backgroundUpdateTimer.setSchedulingType(SchedulingType.FIXED_RATE);
-
-        view.addActionListener(new ActionListener<HostCpuView.Action>() {
-            @Override
-            public void actionPerformed(ActionEvent<Action> actionEvent) {
-                switch (actionEvent.getActionId()) {
-                    case VISIBLE:
-                        start();
-                        break;
-                    case HIDDEN:
-                        stop();
-                        break;
-                    default:
-                        throw new NotImplementedException("unhandled action: " + actionEvent.getActionId());
-                }
-            }
-        });
-
-    }
-
-    // TODO: Consider doing this in a background thread (move to view and use SwingWorker or such).
-    private void updateView() {
-        HostInfo hostInfo = hostInfoDAO.getHostInfo(ref);
-
-        view.setCpuCount(String.valueOf(hostInfo.getCpuCount()));
-        view.setCpuModel(hostInfo.getCpuModel());
-
-        doCpuChartUpdate();
-    }
-
-    private void start() {
-        backgroundUpdateTimer.start();
-    }
-
-    private void stop() {
-        backgroundUpdateTimer.stop();
-    }
-
-    private void doCpuChartUpdate() {
-        List<CpuStat> cpuStats = cpuStatDAO.getLatestCpuStats(ref, lastSeenTimeStamp);
-        List<List<DiscreteTimeData<Double>>> results = new ArrayList<>();
-        for (CpuStat stat : cpuStats) {
-            double[] data = stat.getPerProcessorUsage();
-            for (int i = 0 ; i < data.length; i++) {
-                if (results.size() == i) {
-                    results.add(new ArrayList<DiscreteTimeData<Double>>());
-                }
-                results.get(i).add(new DiscreteTimeData<Double>(stat.getTimeStamp(), data[i]));
-                lastSeenTimeStamp = Math.max(lastSeenTimeStamp, stat.getTimeStamp());
-            }
-        }
-
-        for (int i = 0; i < results.size(); i++) {
-            if (i == chartsAdded) {
-                view.addCpuUsageChart(i, translator.localize(LocaleResources.HOST_CPU_ID, String.valueOf(i)));
-                chartsAdded++;
-            }
-            view.addCpuUsageData(i, results.get(i));
-        }
-    }
-
-    public UIComponent getView() {
-        return view;
-    }
-
-}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/HostInformationController.java	Tue Nov 27 14:45:51 2012 -0500
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/HostInformationController.java	Tue Nov 27 14:47:49 2012 -0500
@@ -41,12 +41,10 @@
 import com.redhat.thermostat.client.core.HostInformationService;
 import com.redhat.thermostat.client.core.controllers.HostInformationServiceController;
 import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.core.views.HostCpuViewProvider;
 import com.redhat.thermostat.client.core.views.HostInformationView;
 import com.redhat.thermostat.client.core.views.HostInformationViewProvider;
 import com.redhat.thermostat.client.core.views.HostMemoryViewProvider;
 import com.redhat.thermostat.client.locale.LocaleResources;
-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;
@@ -57,21 +55,17 @@
 
     private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
 
-    private final HostCpuController cpuController;
     private final HostMemoryController memoryController;
 
     private final HostInformationView view;
 
-    public HostInformationController(UiFacadeFactory uiFacadeFactory, HostInfoDAO hostInfoDao, CpuStatDAO cpuStatDao, MemoryStatDAO memoryStatDao, HostRef ref, HostInformationViewProvider provider) {
+    public HostInformationController(UiFacadeFactory uiFacadeFactory, HostInfoDAO hostInfoDao, MemoryStatDAO memoryStatDao, HostRef ref, HostInformationViewProvider provider) {
         OSGIUtils utils = OSGIUtils.getInstance();
-        HostCpuViewProvider hostCpuProvider = utils.getService(HostCpuViewProvider.class);
         HostMemoryViewProvider hostMemoryProvider = utils.getService(HostMemoryViewProvider.class);
-        cpuController = new HostCpuController(hostInfoDao, cpuStatDao, ref, hostCpuProvider);
         memoryController = new HostMemoryController(hostInfoDao, memoryStatDao, ref, hostMemoryProvider);
 
         view = provider.createView();
 
-        view.addChildView(translator.localize(LocaleResources.HOST_INFO_TAB_CPU), getCpuController().getView());
         view.addChildView(translator.localize(LocaleResources.HOST_INFO_TAB_MEMORY), getMemoryController().getView());
         
         Collection<HostInformationService> hostInfoServices = uiFacadeFactory.getHostInformationServices();
@@ -84,10 +78,6 @@
         }
     }
 
-    public HostCpuController getCpuController() {
-        return cpuController;
-    }
-
     public HostMemoryController getMemoryController() {
         return memoryController;
     }
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/UiFacadeFactory.java	Tue Nov 27 14:45:51 2012 -0500
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/UiFacadeFactory.java	Tue Nov 27 14:47:49 2012 -0500
@@ -41,7 +41,6 @@
 import com.redhat.thermostat.client.core.HostInformationService;
 import com.redhat.thermostat.client.core.VmInformationService;
 import com.redhat.thermostat.client.osgi.service.VMContextAction;
-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;
@@ -54,7 +53,6 @@
 public interface UiFacadeFactory {
 
     void setHostInfoDao(HostInfoDAO hostInfoDao);
-    void setCpuStatDao(CpuStatDAO cpuStatDAO);
     void setMemoryStatDao(MemoryStatDAO memoryStatDAO);
 
     void setVmInfoDao(VmInfoDAO vmInfoDAO);
--- a/client/core/src/main/resources/com/redhat/thermostat/client/locale/strings.properties	Tue Nov 27 14:45:51 2012 -0500
+++ b/client/core/src/main/resources/com/redhat/thermostat/client/locale/strings.properties	Tue Nov 27 14:47:49 2012 -0500
@@ -66,15 +66,9 @@
 HOME_PANEL_SECTION_ISSUES = Issues
 HOME_PANEL_NO_ISSUES = No Issues
 
-HOST_INFO_TAB_CPU = Processor
 HOST_INFO_TAB_MEMORY = Memory
 HOST_INFO_TAB_IO = IO
 
-HOST_CPU_SECTION_OVERVIEW = Processor
-HOST_CPU_ID = Cpu {0}
-HOST_CPU_USAGE_CHART_TIME_LABEL = Time
-HOST_CPU_USAGE_CHART_VALUE_LABEL = Cpu Usage (%)
-
 HOST_MEMORY_SECTION_OVERVIEW = Memory
 HOST_MEMORY_CHART_TITLE = Memory
 HOST_MEMORY_CHART_TIME_LABEL = Time
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/HostCpuControllerTest.java	Tue Nov 27 14:45:51 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,165 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not 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.mockito.Matchers.any;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isNotNull;
-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.Arrays;
-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.core.views.HostCpuView;
-import com.redhat.thermostat.client.core.views.HostCpuViewProvider;
-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.CpuStatDAO;
-import com.redhat.thermostat.common.dao.HostInfoDAO;
-import com.redhat.thermostat.common.dao.HostRef;
-import com.redhat.thermostat.storage.model.CpuStat;
-import com.redhat.thermostat.storage.model.DiscreteTimeData;
-import com.redhat.thermostat.storage.model.HostInfo;
-
-public class HostCpuControllerTest {
-
-    @SuppressWarnings("unused")
-    private HostCpuController controller;
-
-    private HostCpuView view;
-
-    private Timer timer;
-
-    private ActionListener<HostCpuView.Action> viewListener;
-    private Runnable timerAction;
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Before
-    public void setUp() {
-        // Setup timer.
-        ApplicationContextUtil.resetApplicationContext();
-        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);
-
-        // Setup DAOs.
-        HostInfo hostInfo = new HostInfo("fluffhost1", "fluffOs1", "fluffKernel1", "fluffCpu1", 12345, 98765);
-        HostInfoDAO hostInfoDAO = mock(HostInfoDAO.class);
-        when(hostInfoDAO.getHostInfo(any(HostRef.class))).thenReturn(hostInfo);
-
-        CpuStat cpuStat1 = new CpuStat(1l, new double[] {10.0, 20.0, 30.0});
-        CpuStat cpuStat2 = new CpuStat(2l, new double[] {15.0, 25.0, 35.0});
-        CpuStatDAO cpuStatDAO = mock(CpuStatDAO.class);
-        when(cpuStatDAO.getLatestCpuStats(any(HostRef.class), anyLong())).thenReturn(Arrays.asList(cpuStat1, cpuStat2));
-
-        // Set up View
-        view = mock(HostCpuView.class);
-        ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class);
-        doNothing().when(view).addActionListener(viewArgumentCaptor.capture());
-        HostCpuViewProvider viewProvider = mock(HostCpuViewProvider.class);
-        when(viewProvider.createView()).thenReturn(view);
-
-        HostRef host = new HostRef("123", "fluffhost");
-        controller = new HostCpuController(hostInfoDAO, cpuStatDAO, host, viewProvider);
-
-        timerAction = actionCaptor.getValue();
-        viewListener = viewArgumentCaptor.getValue();
-    }
-
-    @After
-    public void tearDown() {
-        timerAction = null;
-        controller = null;
-        view = null;
-        timer = null;
-        ApplicationContextUtil.resetApplicationContext();
-    }
-
-    @Test
-    public void testTimer() {
-        viewListener.actionPerformed(new ActionEvent<>(view, HostCpuView.Action.VISIBLE));
-
-        verify(timer).setAction(isNotNull(Runnable.class));
-        verify(timer).setDelay(5);
-        verify(timer).setTimeUnit(TimeUnit.SECONDS);
-        verify(timer).setInitialDelay(0);
-        verify(timer).setSchedulingType(SchedulingType.FIXED_RATE);
-        verify(timer).start();
-
-        viewListener.actionPerformed(new ActionEvent<>(view, HostCpuView.Action.HIDDEN));
-
-        verify(timer).stop();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testTimerAction() {
-        timerAction.run();
-        verify(view).setCpuModel("fluffCpu1");
-        verify(view).setCpuCount("12345");
-        @SuppressWarnings("rawtypes")
-        ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
-        verify(view).addCpuUsageChart(eq(0), anyString());
-        verify(view).addCpuUsageData(eq(0), captor.capture());
-        List<DiscreteTimeData<Double>> cpuLoadData = captor.getValue();
-        assertEquals(1, cpuLoadData.get(0).getTimeInMillis());
-        assertEquals(10.0, cpuLoadData.get(0).getData().doubleValue(), 0.0001);
-        assertEquals(2, cpuLoadData.get(1).getTimeInMillis());
-        assertEquals(15.0, cpuLoadData.get(1).getData().doubleValue(), 0.0001);
-    }
-}
--- a/client/pom.xml	Tue Nov 27 14:45:51 2012 -0500
+++ b/client/pom.xml	Tue Nov 27 14:47:49 2012 -0500
@@ -66,6 +66,7 @@
     <module>living-vm-filter</module>
     <module>command</module>
     <module>swing</module>
+    <module>swing-components</module>
   </modules>
 
 </project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/swing-components/pom.xml	Tue Nov 27 14:47:49 2012 -0500
@@ -0,0 +1,70 @@
+<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.components,
+              com.redhat.thermostat.swing.components.models,
+              com.redhat.thermostat.swing.components.experimental
+            </Export-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-components/src/main/java/com/redhat/thermostat/swing/components/experimental/WrapLayout.java	Tue Nov 27 14:47:49 2012 -0500
@@ -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.swing.components.experimental;
+
+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/swing/pom.xml	Tue Nov 27 14:45:51 2012 -0500
+++ b/client/swing/pom.xml	Tue Nov 27 14:47:49 2012 -0500
@@ -51,13 +51,18 @@
   <name>Thermostat Swing Client</name>
 
   <dependencies>
-      <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-swing-components</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-laf</artifactId>
       <version>${project.version}</version>
     </dependency>
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/Main.java	Tue Nov 27 14:45:51 2012 -0500
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/Main.java	Tue Nov 27 14:47:49 2012 -0500
@@ -70,11 +70,11 @@
 import com.redhat.thermostat.common.utils.OSGIUtils;
 import com.redhat.thermostat.storage.config.StartupConfiguration;
 import com.redhat.thermostat.storage.core.Connection;
-import com.redhat.thermostat.storage.core.StorageProvider;
-import com.redhat.thermostat.storage.core.StorageProviderUtil;
 import com.redhat.thermostat.storage.core.Connection.ConnectionListener;
 import com.redhat.thermostat.storage.core.Connection.ConnectionStatus;
 import com.redhat.thermostat.storage.core.Connection.ConnectionType;
+import com.redhat.thermostat.storage.core.StorageProvider;
+import com.redhat.thermostat.storage.core.StorageProviderUtil;
 import com.redhat.thermostat.utils.keyring.Keyring;
 
 public class Main {
@@ -282,7 +282,6 @@
                 // register the storage, so other services can request it
                 daoFactory.registerDAOsAndStorageAsOSGiServices();
                 uiFacadeFactory.setHostInfoDao(daoFactory.getHostInfoDAO());
-                uiFacadeFactory.setCpuStatDao(daoFactory.getCpuStatDAO());
                 uiFacadeFactory.setMemoryStatDao(daoFactory.getMemoryStatDAO());
 
                 uiFacadeFactory.setVmInfoDao(daoFactory.getVmInfoDAO());
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/UiFacadeFactoryImpl.java	Tue Nov 27 14:45:51 2012 -0500
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/UiFacadeFactoryImpl.java	Tue Nov 27 14:47:49 2012 -0500
@@ -54,7 +54,6 @@
 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;
@@ -76,7 +75,6 @@
     private BundleContext context;
 
     private HostInfoDAO hostInfoDao;
-    private CpuStatDAO cpuStatDao;
     private MemoryStatDAO memoryStatDao;
 
     private VmInfoDAO vmInfoDao;
@@ -100,10 +98,6 @@
         this.hostInfoDao = hostInfoDao;
     }
 
-    public void setCpuStatDao(CpuStatDAO cpuStatDao) {
-        this.cpuStatDao = cpuStatDao;
-    }
-
     public void setMemoryStatDao(MemoryStatDAO memoryStatDao) {
         this.memoryStatDao = memoryStatDao;
     }
@@ -142,7 +136,7 @@
     @Override
     public HostInformationController getHostController(HostRef ref) {
         HostInformationViewProvider viewProvider = serviceProvider.getService(HostInformationViewProvider.class);
-        return new HostInformationController(this, hostInfoDao, cpuStatDao, memoryStatDao, ref, viewProvider);
+        return new HostInformationController(this, hostInfoDao, memoryStatDao, ref, viewProvider);
     }
 
     @Override
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/WrapLayout.java	Tue Nov 27 14:45:51 2012 -0500
+++ /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.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;
-	}
-}
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/ThermostatActivator.java	Tue Nov 27 14:45:51 2012 -0500
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/ThermostatActivator.java	Tue Nov 27 14:47:49 2012 -0500
@@ -45,7 +45,6 @@
 
 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.SummaryViewProvider;
@@ -60,7 +59,6 @@
 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.SwingSummaryViewProvider;
@@ -91,8 +89,6 @@
         // Host views
         HostInformationViewProvider infoProvider = new SwingHostInformationViewProvider();
         context.registerService(HostInformationViewProvider.class.getName(), infoProvider, null);
-        HostCpuViewProvider cpuProvider = new SwingHostCpuViewProvider();
-        context.registerService(HostCpuViewProvider.class.getName(), cpuProvider, null);
         HostMemoryViewProvider memoryProvider = new SwingHostMemoryViewProvider();
         context.registerService(HostMemoryViewProvider.class.getName(), memoryProvider, null);
         
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/HostCpuPanel.java	Tue Nov 27 14:45:51 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,297 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not 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.storage.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/swing/src/main/java/com/redhat/thermostat/client/swing/views/HostMemoryPanel.java	Tue Nov 27 14:45:51 2012 -0500
+++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/HostMemoryPanel.java	Tue Nov 27 14:47:49 2012 -0500
@@ -69,7 +69,6 @@
 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;
@@ -78,6 +77,7 @@
 import com.redhat.thermostat.common.utils.DisplayableValues;
 import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
 import com.redhat.thermostat.storage.model.DiscreteTimeData;
+import com.redhat.thermostat.swing.components.experimental.WrapLayout;
 
 public class HostMemoryPanel extends HostMemoryView implements SwingComponent {
 
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/views/SwingHostCpuViewProvider.java	Tue Nov 27 14:45:51 2012 -0500
+++ /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.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();
-    }
-
-}
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/osgi/ThermostatActivatorTest.java	Tue Nov 27 14:45:51 2012 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/osgi/ThermostatActivatorTest.java	Tue Nov 27 14:47:49 2012 -0500
@@ -43,7 +43,6 @@
 
 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.SummaryViewProvider;
@@ -55,7 +54,6 @@
 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.SwingSummaryViewProvider;
@@ -79,7 +77,6 @@
         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(VmInformationViewProvider.class.getName(), SwingVmInformationViewProvider.class));
         assertTrue(ctx.isServiceRegistered(VmCpuViewProvider.class.getName(), SwingVmCpuViewProvider.class));
         assertTrue(ctx.isServiceRegistered(VmGcViewProvider.class.getName(), SwingVmGcViewProvider.class));
@@ -87,6 +84,6 @@
         assertTrue(ctx.isServiceRegistered(AgentInformationViewProvider.class.getName(), SwingAgentInformationViewProvider.class));
         assertTrue(ctx.isServiceRegistered(ClientConfigViewProvider.class.getName(), SwingClientConfigurationViewProvider.class));
         
-        assertEquals(11, ctx.getAllServices().size());
+        assertEquals(10, ctx.getAllServices().size());
     }
 }
--- a/distribution/config/commands/gui.properties	Tue Nov 27 14:45:51 2012 -0500
+++ b/distribution/config/commands/gui.properties	Tue Nov 27 14:47:49 2012 -0500
@@ -5,9 +5,12 @@
           thermostat-common-command-@project.version@.jar, \
           thermostat-client-core-@project.version@.jar, \
           thermostat-client-swing-@project.version@.jar, \
+          thermostat-swing-components-@project.version@.jar, \
           thermostat-client-command-@project.version@.jar, \
           thermostat-host-overview-client-core-@project.version@.jar, \
           thermostat-host-overview-client-swing-@project.version@.jar, \
+          thermostat-host-cpu-client-core-@project.version@.jar, \
+          thermostat-host-cpu-client-swing-@project.version@.jar, \
           thermostat-client-heapdumper-core-@project.version@.jar, \
           thermostat-client-heapdumper-swing-@project.version@.jar, \
           thermostat-killvm-client-swing-@project.version@.jar, \
--- a/distribution/pom.xml	Tue Nov 27 14:45:51 2012 -0500
+++ b/distribution/pom.xml	Tue Nov 27 14:47:49 2012 -0500
@@ -303,6 +303,11 @@
     </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>
@@ -318,6 +323,16 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-host-cpu-client-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-host-cpu-client-swing</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-client-vmclassstat-swing</artifactId>
       <version>${project.version}</version>
     </dependency>
--- a/eclipse/com.redhat.thermostat.client.feature/feature.xml	Tue Nov 27 14:45:51 2012 -0500
+++ b/eclipse/com.redhat.thermostat.client.feature/feature.xml	Tue Nov 27 14:47:49 2012 -0500
@@ -133,4 +133,11 @@
          version="0.0.0"
          unpack="false"/>
 
+   <plugin
+         id="com.redhat.thermostat.host.cpu.client.core"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
 </feature>
--- a/eclipse/com.redhat.thermostat.client.feature/pom.xml	Tue Nov 27 14:45:51 2012 -0500
+++ b/eclipse/com.redhat.thermostat.client.feature/pom.xml	Tue Nov 27 14:47:49 2012 -0500
@@ -26,6 +26,11 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-host-cpu-client-core</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-client-vmclassstat-core</artifactId>
       <version>0.5.0-SNAPSHOT</version>
     </dependency>
--- a/eclipse/com.redhat.thermostat.eclipse.chart.common/META-INF/MANIFEST.MF	Tue Nov 27 14:45:51 2012 -0500
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/META-INF/MANIFEST.MF	Tue Nov 27 14:47:49 2012 -0500
@@ -7,6 +7,8 @@
 Bundle-Vendor: Red Hat Inc.
 Bundle-RequiredExecutionEnvironment: JavaSE-1.7
 Import-Package: com.redhat.thermostat.client.core.views,
+ com.redhat.thermostat.host.cpu.client.core,
+ com.redhat.thermostat.host.cpu.client.locale,
  com.redhat.thermostat.client.locale,
  com.redhat.thermostat.client.osgi.service,
  com.redhat.thermostat.client.ui,
@@ -15,11 +17,11 @@
  com.redhat.thermostat.common.dao,
  com.redhat.thermostat.common.heap,
  com.redhat.thermostat.common.locale,
- com.redhat.thermostat.storage.model,
- com.redhat.thermostat.storage.core,
  com.redhat.thermostat.common.utils,
  com.redhat.thermostat.eclipse,
  com.redhat.thermostat.eclipse.views,
+ com.redhat.thermostat.storage.core,
+ com.redhat.thermostat.storage.model,
  org.jfree.chart,
  org.jfree.chart.axis,
  org.jfree.chart.event,
--- a/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/Activator.java	Tue Nov 27 14:45:51 2012 -0500
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/Activator.java	Tue Nov 27 14:47:49 2012 -0500
@@ -39,11 +39,11 @@
 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;
+import com.redhat.thermostat.host.cpu.client.core.HostCpuViewProvider;
 
 public class Activator extends AbstractUIPlugin {
 
--- a/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/HostCpuViewPart.java	Tue Nov 27 14:45:51 2012 -0500
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/HostCpuViewPart.java	Tue Nov 27 14:47:49 2012 -0500
@@ -38,14 +38,14 @@
 
 import org.eclipse.swt.widgets.Composite;
 
-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.SWTComponent;
 import com.redhat.thermostat.eclipse.views.HostRefViewPart;
+import com.redhat.thermostat.host.cpu.client.core.HostCpuController;
+import com.redhat.thermostat.host.cpu.client.core.HostCpuViewProvider;
 
 public class HostCpuViewPart extends HostRefViewPart {
 
--- a/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/SWTHostCpuView.java	Tue Nov 27 14:45:51 2012 -0500
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/SWTHostCpuView.java	Tue Nov 27 14:47:49 2012 -0500
@@ -62,8 +62,8 @@
 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.host.cpu.client.core.HostCpuView;
+import com.redhat.thermostat.host.cpu.client.locale.LocaleResources;
 import com.redhat.thermostat.client.ui.ChartColors;
 import com.redhat.thermostat.common.locale.Translate;
 import com.redhat.thermostat.eclipse.SWTComponent;
--- a/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/SWTHostCpuViewProvider.java	Tue Nov 27 14:45:51 2012 -0500
+++ b/eclipse/com.redhat.thermostat.eclipse.chart.common/src/com/redhat/thermostat/eclipse/chart/common/SWTHostCpuViewProvider.java	Tue Nov 27 14:47:49 2012 -0500
@@ -36,9 +36,9 @@
 
 package com.redhat.thermostat.eclipse.chart.common;
 
-import com.redhat.thermostat.client.core.views.HostCpuView;
-import com.redhat.thermostat.client.core.views.HostCpuViewProvider;
 import com.redhat.thermostat.eclipse.SWTViewProvider;
+import com.redhat.thermostat.host.cpu.client.core.HostCpuView;
+import com.redhat.thermostat.host.cpu.client.core.HostCpuViewProvider;
 
 public class SWTHostCpuViewProvider extends SWTViewProvider implements
         HostCpuViewProvider {
--- a/eclipse/com.redhat.thermostat.eclipse.test.ui/META-INF/MANIFEST.MF	Tue Nov 27 14:45:51 2012 -0500
+++ b/eclipse/com.redhat.thermostat.eclipse.test.ui/META-INF/MANIFEST.MF	Tue Nov 27 14:47:49 2012 -0500
@@ -10,6 +10,7 @@
  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.host.cpu.client.core,
  com.redhat.thermostat.host.overview.client.core,
  com.redhat.thermostat.client.osgi.service,
  com.redhat.thermostat.client.ui,
--- a/eclipse/com.redhat.thermostat.eclipse.test/META-INF/MANIFEST.MF	Tue Nov 27 14:45:51 2012 -0500
+++ b/eclipse/com.redhat.thermostat.eclipse.test/META-INF/MANIFEST.MF	Tue Nov 27 14:47:49 2012 -0500
@@ -13,6 +13,7 @@
  com.redhat.thermostat.bundles.org.mockito.mockito-core;resolution:=optional
 Bundle-RequiredExecutionEnvironment: JavaSE-1.7
 Import-Package: com.redhat.thermostat.client.core.views,
+ com.redhat.thermostat.host.cpu.client.core,
  com.redhat.thermostat.host.overview.client.core,
  com.redhat.thermostat.client.osgi.service,
  com.redhat.thermostat.client.ui,
--- a/eclipse/com.redhat.thermostat.eclipse.test/src/com/redhat/thermostat/eclipse/test/views/HostCpuViewPartTest.java	Tue Nov 27 14:45:51 2012 -0500
+++ b/eclipse/com.redhat.thermostat.eclipse.test/src/com/redhat/thermostat/eclipse/test/views/HostCpuViewPartTest.java	Tue Nov 27 14:47:49 2012 -0500
@@ -50,9 +50,7 @@
 import org.junit.Test;
 import org.mockito.InOrder;
 
-import com.redhat.thermostat.client.core.views.HostCpuViewProvider;
 import com.redhat.thermostat.client.core.views.UIComponent;
-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;
@@ -62,6 +60,8 @@
 import com.redhat.thermostat.eclipse.chart.common.SWTHostCpuView;
 import com.redhat.thermostat.eclipse.chart.common.SWTHostCpuViewProvider;
 import com.redhat.thermostat.eclipse.internal.views.RefViewPart;
+import com.redhat.thermostat.host.cpu.client.core.HostCpuController;
+import com.redhat.thermostat.host.cpu.client.core.HostCpuViewProvider;
 
 public class HostCpuViewPartTest extends AbstractRefViewPartTest<HostRef> {
     
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host-cpu/client-core/pom.xml	Tue Nov 27 14:47:49 2012 -0500
@@ -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-host-cpu</artifactId>
+    <groupId>com.redhat.thermostat</groupId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>thermostat-host-cpu-client-core</artifactId>
+  <packaging>bundle</packaging>
+  <name>Thermostat Host CPU Core Client 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.host.cpu.client.core</Bundle-SymbolicName>
+            <Export-Package>
+              com.redhat.thermostat.host.cpu.client.core,
+              com.redhat.thermostat.host.cpu.client.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/host-cpu/client-core/src/main/java/com/redhat/thermostat/host/cpu/client/core/HostCpuController.java	Tue Nov 27 14:47:49 2012 -0500
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.host.cpu.client.core;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import com.redhat.thermostat.client.core.controllers.HostInformationServiceController;
+import com.redhat.thermostat.client.core.views.BasicView.Action;
+import com.redhat.thermostat.client.core.views.UIComponent;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.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.CpuStatDAO;
+import com.redhat.thermostat.common.dao.HostInfoDAO;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.host.cpu.client.locale.LocaleResources;
+import com.redhat.thermostat.storage.model.CpuStat;
+import com.redhat.thermostat.storage.model.DiscreteTimeData;
+import com.redhat.thermostat.storage.model.HostInfo;
+
+public class HostCpuController implements HostInformationServiceController {
+
+    private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer();
+
+    private final HostCpuView view;
+    private final Timer backgroundUpdateTimer;
+
+    private final HostInfoDAO hostInfoDAO;
+    private final CpuStatDAO cpuStatDAO;
+    private final HostRef ref;
+
+    private int chartsAdded = 0;
+    private long lastSeenTimeStamp = Long.MIN_VALUE;
+
+    public HostCpuController(HostInfoDAO hostInfoDao, CpuStatDAO cpuStatDAO, HostRef ref, HostCpuViewProvider provider) {
+        this.ref = ref;
+        view = provider.createView();
+        view.clearCpuUsageData();
+        this.hostInfoDAO = hostInfoDao;
+        this.cpuStatDAO = cpuStatDAO;
+
+        backgroundUpdateTimer = ApplicationContext.getInstance().getTimerFactory().createTimer();
+        backgroundUpdateTimer.setAction(new Runnable() {
+
+            @Override
+            public void run() {
+                updateView();
+            }
+
+        });
+        backgroundUpdateTimer.setInitialDelay(0);
+        backgroundUpdateTimer.setDelay(5);
+        backgroundUpdateTimer.setTimeUnit(TimeUnit.SECONDS);
+        backgroundUpdateTimer.setSchedulingType(SchedulingType.FIXED_RATE);
+
+        view.addActionListener(new ActionListener<HostCpuView.Action>() {
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                switch (actionEvent.getActionId()) {
+                    case VISIBLE:
+                        start();
+                        break;
+                    case HIDDEN:
+                        stop();
+                        break;
+                    default:
+                        throw new NotImplementedException("unhandled action: " + actionEvent.getActionId());
+                }
+            }
+        });
+
+    }
+
+    // TODO: Consider doing this in a background thread (move to view and use SwingWorker or such).
+    private void updateView() {
+        HostInfo hostInfo = hostInfoDAO.getHostInfo(ref);
+
+        view.setCpuCount(String.valueOf(hostInfo.getCpuCount()));
+        view.setCpuModel(hostInfo.getCpuModel());
+
+        doCpuChartUpdate();
+    }
+
+    private void start() {
+        backgroundUpdateTimer.start();
+    }
+
+    private void stop() {
+        backgroundUpdateTimer.stop();
+    }
+
+    private void doCpuChartUpdate() {
+        List<CpuStat> cpuStats = cpuStatDAO.getLatestCpuStats(ref, lastSeenTimeStamp);
+        List<List<DiscreteTimeData<Double>>> results = new ArrayList<>();
+        for (CpuStat stat : cpuStats) {
+            double[] data = stat.getPerProcessorUsage();
+            for (int i = 0 ; i < data.length; i++) {
+                if (results.size() == i) {
+                    results.add(new ArrayList<DiscreteTimeData<Double>>());
+                }
+                results.get(i).add(new DiscreteTimeData<Double>(stat.getTimeStamp(), data[i]));
+                lastSeenTimeStamp = Math.max(lastSeenTimeStamp, stat.getTimeStamp());
+            }
+        }
+
+        for (int i = 0; i < results.size(); i++) {
+            if (i == chartsAdded) {
+                view.addCpuUsageChart(i, translator.localize(LocaleResources.HOST_CPU_ID, String.valueOf(i)));
+                chartsAdded++;
+            }
+            view.addCpuUsageData(i, results.get(i));
+        }
+    }
+
+    public UIComponent getView() {
+        return view;
+    }
+
+    @Override
+    public String getLocalizedName() {
+        return translator.localize(LocaleResources.HOST_INFO_TAB_CPU);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host-cpu/client-core/src/main/java/com/redhat/thermostat/host/cpu/client/core/HostCpuService.java	Tue Nov 27 14:47:49 2012 -0500
@@ -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.host.cpu.client.core;
+
+import com.redhat.thermostat.client.core.HostFilter;
+import com.redhat.thermostat.client.core.HostInformationService;
+import com.redhat.thermostat.client.core.controllers.HostInformationServiceController;
+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;
+
+public class HostCpuService implements HostInformationService {
+    
+    private static final HostFilter FILTER = new HostFilter() {
+        @Override
+        public boolean matches(HostRef toMatch) {
+            return true;
+        }
+    };
+    
+    private HostInfoDAO hostInfoDAO;
+    private CpuStatDAO cpuStatDAO;
+    
+    public HostCpuService(HostInfoDAO hostInfoDAO, CpuStatDAO cpuStatDAO) {
+        this.hostInfoDAO = hostInfoDAO;
+        this.cpuStatDAO = cpuStatDAO;
+    }
+
+    @Override
+    public HostFilter getFilter() {
+        return FILTER;
+    }
+
+    @Override
+    public HostInformationServiceController getInformationServiceController(
+            HostRef ref) {
+        HostCpuViewProvider provider = OSGIUtils.getInstance().getService(HostCpuViewProvider.class);
+        return new HostCpuController(hostInfoDAO, cpuStatDAO, ref, provider);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host-cpu/client-core/src/main/java/com/redhat/thermostat/host/cpu/client/core/HostCpuView.java	Tue Nov 27 14:47:49 2012 -0500
@@ -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.host.cpu.client.core;
+
+import java.util.List;
+
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.core.views.UIComponent;
+import com.redhat.thermostat.storage.model.DiscreteTimeData;
+
+public abstract class HostCpuView extends BasicView implements UIComponent {
+
+    public abstract void setCpuCount(String count);
+
+    public abstract void setCpuModel(String model);
+
+    public abstract void clearCpuUsageData();
+
+    public abstract void addCpuUsageChart(int cpuIndex, String humanReadableName);
+
+    public abstract void addCpuUsageData(int cpuIndex, List<DiscreteTimeData<Double>> data);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host-cpu/client-core/src/main/java/com/redhat/thermostat/host/cpu/client/core/HostCpuViewProvider.java	Tue Nov 27 14:47:49 2012 -0500
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.host.cpu.client.core;
+
+import com.redhat.thermostat.client.core.views.ViewProvider;
+
+public interface HostCpuViewProvider extends ViewProvider {
+
+    @Override
+    HostCpuView createView();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host-cpu/client-core/src/main/java/com/redhat/thermostat/host/cpu/client/locale/LocaleResources.java	Tue Nov 27 14:47:49 2012 -0500
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.host.cpu.client.locale;
+
+import com.redhat.thermostat.common.locale.Translate;
+
+public enum LocaleResources {
+    HOST_INFO_TAB_CPU,
+    
+    HOST_INFO_CPU_COUNT,
+    HOST_INFO_CPU_MODEL,
+    
+    HOST_CPU_SECTION_OVERVIEW,
+    HOST_CPU_ID,
+    HOST_CPU_USAGE_CHART_TIME_LABEL,
+    HOST_CPU_USAGE_CHART_VALUE_LABEL,
+    ;
+
+    static final String RESOURCE_BUNDLE =
+            "com.redhat.thermostat.host.cpu.client.locale.strings";
+
+    public static Translate<LocaleResources> createLocalizer() {
+        return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host-cpu/client-core/src/main/resources/com/redhat/thermostat/host/cpu/client/locale/strings.properties	Tue Nov 27 14:47:49 2012 -0500
@@ -0,0 +1,9 @@
+HOST_INFO_TAB_CPU = Processor
+
+HOST_INFO_CPU_COUNT = Processor Count
+HOST_INFO_CPU_MODEL = Processor Model
+
+HOST_CPU_SECTION_OVERVIEW = Processor
+HOST_CPU_ID = Cpu {0}
+HOST_CPU_USAGE_CHART_TIME_LABEL = Time
+HOST_CPU_USAGE_CHART_VALUE_LABEL = Cpu Usage (%)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host-cpu/client-core/src/test/java/com/redhat/thermostat/host/cpu/client/core/HostCpuControllerTest.java	Tue Nov 27 14:47:49 2012 -0500
@@ -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.host.cpu.client.core;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNotNull;
+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.Arrays;
+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.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.CpuStatDAO;
+import com.redhat.thermostat.common.dao.HostInfoDAO;
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.host.cpu.client.core.HostCpuController;
+import com.redhat.thermostat.host.cpu.client.core.HostCpuView;
+import com.redhat.thermostat.host.cpu.client.core.HostCpuViewProvider;
+import com.redhat.thermostat.storage.model.CpuStat;
+import com.redhat.thermostat.storage.model.DiscreteTimeData;
+import com.redhat.thermostat.storage.model.HostInfo;
+
+public class HostCpuControllerTest {
+
+    @SuppressWarnings("unused")
+    private HostCpuController controller;
+
+    private HostCpuView view;
+
+    private Timer timer;
+
+    private ActionListener<HostCpuView.Action> viewListener;
+    private Runnable timerAction;
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Before
+    public void setUp() {
+        // Setup timer.
+        ApplicationContextUtil.resetApplicationContext();
+        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);
+
+        // Setup DAOs.
+        HostInfo hostInfo = new HostInfo("fluffhost1", "fluffOs1", "fluffKernel1", "fluffCpu1", 12345, 98765);
+        HostInfoDAO hostInfoDAO = mock(HostInfoDAO.class);
+        when(hostInfoDAO.getHostInfo(any(HostRef.class))).thenReturn(hostInfo);
+
+        CpuStat cpuStat1 = new CpuStat(1l, new double[] {10.0, 20.0, 30.0});
+        CpuStat cpuStat2 = new CpuStat(2l, new double[] {15.0, 25.0, 35.0});
+        CpuStatDAO cpuStatDAO = mock(CpuStatDAO.class);
+        when(cpuStatDAO.getLatestCpuStats(any(HostRef.class), anyLong())).thenReturn(Arrays.asList(cpuStat1, cpuStat2));
+
+        // Set up View
+        view = mock(HostCpuView.class);
+        ArgumentCaptor<ActionListener> viewArgumentCaptor = ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addActionListener(viewArgumentCaptor.capture());
+        HostCpuViewProvider viewProvider = mock(HostCpuViewProvider.class);
+        when(viewProvider.createView()).thenReturn(view);
+
+        HostRef host = new HostRef("123", "fluffhost");
+        controller = new HostCpuController(hostInfoDAO, cpuStatDAO, host, viewProvider);
+
+        timerAction = actionCaptor.getValue();
+        viewListener = viewArgumentCaptor.getValue();
+    }
+
+    @After
+    public void tearDown() {
+        timerAction = null;
+        controller = null;
+        view = null;
+        timer = null;
+        ApplicationContextUtil.resetApplicationContext();
+    }
+
+    @Test
+    public void testTimer() {
+        viewListener.actionPerformed(new ActionEvent<>(view, HostCpuView.Action.VISIBLE));
+
+        verify(timer).setAction(isNotNull(Runnable.class));
+        verify(timer).setDelay(5);
+        verify(timer).setTimeUnit(TimeUnit.SECONDS);
+        verify(timer).setInitialDelay(0);
+        verify(timer).setSchedulingType(SchedulingType.FIXED_RATE);
+        verify(timer).start();
+
+        viewListener.actionPerformed(new ActionEvent<>(view, HostCpuView.Action.HIDDEN));
+
+        verify(timer).stop();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testTimerAction() {
+        timerAction.run();
+        verify(view).setCpuModel("fluffCpu1");
+        verify(view).setCpuCount("12345");
+        @SuppressWarnings("rawtypes")
+        ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
+        verify(view).addCpuUsageChart(eq(0), anyString());
+        verify(view).addCpuUsageData(eq(0), captor.capture());
+        List<DiscreteTimeData<Double>> cpuLoadData = captor.getValue();
+        assertEquals(1, cpuLoadData.get(0).getTimeInMillis());
+        assertEquals(10.0, cpuLoadData.get(0).getData().doubleValue(), 0.0001);
+        assertEquals(2, cpuLoadData.get(1).getTimeInMillis());
+        assertEquals(15.0, cpuLoadData.get(1).getData().doubleValue(), 0.0001);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host-cpu/client-swing/pom.xml	Tue Nov 27 14:47:49 2012 -0500
@@ -0,0 +1,87 @@
+<?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-host-cpu</artifactId>
+    <groupId>com.redhat.thermostat</groupId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>thermostat-host-cpu-client-swing</artifactId>
+  <packaging>bundle</packaging>
+  <name>Thermostat Host CPU Swing Client 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.host.cpu.client.swing</Private-Package>
+            <Bundle-Activator>com.redhat.thermostat.host.cpu.client.swing.Activator</Bundle-Activator>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-SymbolicName>com.redhat.thermostat.host.cpu.client.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-swing-components</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-host-cpu-client-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host-cpu/client-swing/src/main/java/com/redhat/thermostat/host/cpu/client/swing/Activator.java	Tue Nov 27 14:47:49 2012 -0500
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.host.cpu.client.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.HostInformationService;
+import com.redhat.thermostat.common.MultipleServiceTracker;
+import com.redhat.thermostat.common.MultipleServiceTracker.Action;
+import com.redhat.thermostat.common.dao.CpuStatDAO;
+import com.redhat.thermostat.common.dao.HostInfoDAO;
+import com.redhat.thermostat.host.cpu.client.core.HostCpuService;
+import com.redhat.thermostat.host.cpu.client.core.HostCpuViewProvider;
+
+public class Activator implements BundleActivator {
+    
+    private MultipleServiceTracker tracker;
+    private ServiceRegistration reg;
+
+    @Override
+    public void start(final BundleContext context) throws Exception {
+        HostCpuViewProvider viewProvider = new SwingHostCpuViewProvider();
+        context.registerService(HostCpuViewProvider.class.getName(), viewProvider, null);
+
+        Class<?>[] deps = new Class<?>[] {
+            HostInfoDAO.class,
+            CpuStatDAO.class,
+        };
+
+        tracker = new MultipleServiceTracker(context, deps, new Action() {
+
+            @Override
+            public void dependenciesAvailable(Map<String, Object> services) {
+                HostInfoDAO hostInfoDAO = (HostInfoDAO) services.get(HostInfoDAO.class.getName());
+                Objects.requireNonNull(hostInfoDAO);
+                CpuStatDAO cpuStatDAO = (CpuStatDAO) services.get(CpuStatDAO.class.getName());
+                Objects.requireNonNull(cpuStatDAO);
+                HostCpuService service = new HostCpuService(hostInfoDAO, cpuStatDAO);
+                reg = context.registerService(HostInformationService.class.getName(), service, null);
+            }
+
+            @Override
+            public void dependenciesUnavailable() {
+                reg.unregister();
+            }
+
+        });
+        tracker.open();
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        tracker.close();
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host-cpu/client-swing/src/main/java/com/redhat/thermostat/host/cpu/client/swing/HostCpuPanel.java	Tue Nov 27 14:47:49 2012 -0500
@@ -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.host.cpu.client.swing;
+
+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.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.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.host.cpu.client.core.HostCpuView;
+import com.redhat.thermostat.host.cpu.client.locale.LocaleResources;
+import com.redhat.thermostat.storage.model.DiscreteTimeData;
+import com.redhat.thermostat.swing.components.experimental.WrapLayout;
+
+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/host-cpu/client-swing/src/main/java/com/redhat/thermostat/host/cpu/client/swing/SwingHostCpuViewProvider.java	Tue Nov 27 14:47:49 2012 -0500
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.host.cpu.client.swing;
+
+import com.redhat.thermostat.host.cpu.client.core.HostCpuView;
+import com.redhat.thermostat.host.cpu.client.core.HostCpuViewProvider;
+
+public class SwingHostCpuViewProvider implements HostCpuViewProvider {
+
+    @Override
+    public HostCpuView createView() {
+        return new HostCpuPanel();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host-cpu/client-swing/src/test/java/com/redhat/thermostat/host/cpu/client/swing/ActivatorTest.java	Tue Nov 27 14:47:49 2012 -0500
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */ 
+
+package com.redhat.thermostat.host.cpu.client.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.HostInformationService;
+import com.redhat.thermostat.common.dao.CpuStatDAO;
+import com.redhat.thermostat.common.dao.HostInfoDAO;
+import com.redhat.thermostat.host.cpu.client.core.HostCpuService;
+import com.redhat.thermostat.host.cpu.client.core.HostCpuViewProvider;
+import com.redhat.thermostat.host.cpu.client.swing.Activator;
+import com.redhat.thermostat.host.cpu.client.swing.SwingHostCpuViewProvider;
+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();
+        HostInfoDAO hostInfoDAO = mock(HostInfoDAO.class);
+        CpuStatDAO cpuStatDAO = mock(CpuStatDAO.class);
+
+        context.registerService(HostInfoDAO.class, hostInfoDAO, null);
+        context.registerService(CpuStatDAO.class, cpuStatDAO, null);
+
+        Activator activator = new Activator();
+
+        activator.start(context);
+
+        assertTrue(context.isServiceRegistered(HostInformationService.class.getName(), HostCpuService.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(HostCpuViewProvider.class.getName(), SwingHostCpuViewProvider.class));
+        assertEquals(1, ctx.getAllServices().size());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/host-cpu/pom.xml	Tue Nov 27 14:47:49 2012 -0500
@@ -0,0 +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</artifactId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>thermostat-host-cpu</artifactId>
+  <packaging>pom</packaging>
+
+  <name>Thermostat Host CPU plugin</name>
+
+  <modules>
+    <module>client-core</module>
+    <module>client-swing</module>
+  </modules>
+
+</project>
--- a/pom.xml	Tue Nov 27 14:45:51 2012 -0500
+++ b/pom.xml	Tue Nov 27 14:47:49 2012 -0500
@@ -132,6 +132,7 @@
     <module>gc</module>
     <module>storage</module>
     <module>host-overview</module>
+    <module>host-cpu</module>
     <!-- development related modules -->
     <module>dev</module>
   </modules>