changeset 719:bc32ec1a9cbc

Move Swing-dependent code into separate bundles: memory-stats-panel This commit splits the memory-stats-panel bundle into core and swing bundles. Reviewed-by: omajid Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-October/003814.html
author Elliott Baron <ebaron@redhat.com>
date Tue, 23 Oct 2012 11:22:31 -0400
parents 2f6384fbe64a
children 4899326c902d
files client/memory-stats-panel/core/pom.xml client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/MemoryMeter.java client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/MemoryStatsController.java client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/MemoryStatsService.java client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/MemoryStatsView.java client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/MemoryStatsViewProvider.java client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/Payload.java client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/RangeModel.java client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/StatsModel.java client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/locale/LocaleResources.java client/memory-stats-panel/core/src/main/resources/com/redhat/thermostat/client/stats/memory/locale/strings.properties client/memory-stats-panel/core/src/test/java/com/redhat/thermostat/client/stats/memory/core/MemoryStatsControllerTest.java client/memory-stats-panel/core/src/test/java/com/redhat/thermostat/client/stats/memory/core/PayloadTest.java client/memory-stats-panel/core/src/test/java/com/redhat/thermostat/client/stats/memory/core/RangeModelTest.java client/memory-stats-panel/core/src/test/java/com/redhat/thermostat/client/stats/memory/core/StatsModelTest.java client/memory-stats-panel/core/src/test/java/com/redhat/thermostat/client/stats/memory/core/locale/TranslateTest.java client/memory-stats-panel/pom.xml client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryGraphPanel.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryMeter.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsController.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsPanelActivator.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsService.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsView.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsViewImpl.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsViewProvider.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/Payload.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/RangeModel.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/StatsModel.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/SwingMemoryStatsViewProvider.java client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/locale/LocaleResources.java client/memory-stats-panel/src/main/resources/com/redhat/thermostat/client/stats/memory/locale/strings.properties client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/MemoryStatsControllerTest.java client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/MemoryStatsPanelActivatorTest.java client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/PayloadTest.java client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/RangeModelTest.java client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/StatsModelTest.java client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/locale/TranslateTest.java client/memory-stats-panel/swing/pom.xml client/memory-stats-panel/swing/src/main/java/com/redhat/thermostat/client/stats/memory/swing/MemoryGraphPanel.java client/memory-stats-panel/swing/src/main/java/com/redhat/thermostat/client/stats/memory/swing/MemoryStatsPanelActivator.java client/memory-stats-panel/swing/src/main/java/com/redhat/thermostat/client/stats/memory/swing/MemoryStatsViewImpl.java client/memory-stats-panel/swing/src/main/java/com/redhat/thermostat/client/stats/memory/swing/SwingMemoryStatsViewProvider.java client/memory-stats-panel/swing/src/main/resources/com/redhat/thermostat/client/stats/memory/locale/strings.properties client/memory-stats-panel/swing/src/test/java/com/redhat/thermostat/client/stats/memory/swing/MemoryStatsPanelActivatorTest.java
diffstat 44 files changed, 2560 insertions(+), 2414 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/pom.xml	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>thermostat-osgi-memory-stats-panel</artifactId>
+    <groupId>com.redhat.thermostat</groupId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>thermostat-osgi-memory-stats-panel-core</artifactId>
+  <packaging>bundle</packaging>
+  <name>Thermostat Client VM Memory Monitor Core plugin</name>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+                com.redhat.thermostat.client.stats.memory.core,
+                   com.redhat.thermostat.client.stats.memory.core.locale,
+            </Export-Package>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-SymbolicName>com.redhat.thermostat.client.stats.memory.core</Bundle-SymbolicName>
+            <!-- Do not autogenerate uses clauses in Manifests -->
+            <_nouses>true</_nouses>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jfree</groupId>
+      <artifactId>jfreechart</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-client-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/MemoryMeter.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,433 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.core;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Insets;
+import java.awt.Paint;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
+import java.awt.image.BufferedImage;
+import java.beans.Transient;
+
+import javax.swing.JComponent;
+import javax.swing.plaf.ColorUIResource;
+
+import sun.swing.SwingUtilities2;
+
+@SuppressWarnings({ "restriction", "serial" })
+public class MemoryMeter extends JComponent {
+    
+    // TODO the font should be customizable
+    private static final Font font = new Font("SansSerif", Font.PLAIN, 10);
+    
+    private static final int TICK_NUM = 100;
+    private static final int SMALL_TICK_NUM = 5;
+    
+    private static final int MAIN_BAR_HEIGHT = 20;
+    
+    private static final ColorUIResource MAIN_GRADIENT_TOP = new ColorUIResource(0xf1f3f1);
+    private static final ColorUIResource MAIN_BORDER_COLOR = new ColorUIResource(0xa8aca8);
+    
+    private static final ColorUIResource MAIN_BAR_BASE_COLOR_TOP = new ColorUIResource(0xbcd5ef);
+    private static final ColorUIResource MAIN_BAR_BASE_COLOR = new ColorUIResource(0x4A90D9);
+    
+    //private static final ColorUIResource STATS_BG = new ColorUIResource(0xF8F8F8);
+    private static final ColorUIResource STATS_BG = new ColorUIResource(0xFFFFFF);
+    
+    private ColorUIResource tickColor;
+    
+    private RangeModel primary;
+    private RangeModel secondary;
+    
+    private Insets boundInsets;
+    
+    private RangeModel internalSecondaryModel;
+    
+    private StatsModel primaryStats;
+    
+    private String primaryUnit;
+    private String secondaryUnit;
+
+        public void setPrimaryScaleUnit(String primaryUnit) {
+        this.primaryUnit = primaryUnit;
+    }
+    
+    public void setSecondayScaleUnit(String secondaryUnit) {
+        this.secondaryUnit = secondaryUnit;
+    }
+    
+    public StatsModel getStats() {
+        return primaryStats;
+    }
+    
+    public void setStats(StatsModel primaryStats) {
+        this.primaryStats = primaryStats;
+    }
+
+    public MemoryMeter() {
+        
+        secondaryUnit = "";
+        primaryUnit = "";
+        
+        boundInsets = new Insets(10, 10, 20, 20);
+        
+        tickColor = new ColorUIResource(0xdbdddb);
+        
+        primary = new RangeModel();
+        primary.setMinimum(0);
+        primary.setMaximum(100);
+        primary.setMinNormalized(0);
+        primary.setMaxNormalized(100);
+        
+        secondary = new RangeModel();
+        secondary.setMinimum(0);
+        secondary.setMaximum(100);
+        secondary.setMinNormalized(0);
+        secondary.setMaxNormalized(100);
+        
+        internalSecondaryModel = new RangeModel();
+    }
+    
+    public ColorUIResource getTickColor() {
+        return tickColor;
+    }
+    
+    public void setTickColor(ColorUIResource tickColor) {
+        this.tickColor = tickColor;
+    }
+    
+    public RangeModel getPrimaryModel() {
+        return primary;
+    }
+    
+    public RangeModel getSecondaryModel() {
+        return secondary;
+    }
+    
+    protected Rectangle getOuterBounds() {
+        return new Rectangle(0, 0, getWidth(), getHeight());
+    }
+    
+    protected Rectangle getBoundsWithInsets(Rectangle bounds) {
+        return new Rectangle(bounds.x + boundInsets.left,
+                             bounds.y + boundInsets.top,
+                             bounds.width  - boundInsets.right,
+                             bounds.height - boundInsets.bottom);
+    }
+        
+    /**
+     * paint the outher frame, including the light border sorrounding
+     */
+    protected void paintOuterFrame(Graphics2D graphics, Rectangle bounds) {
+
+        RoundRectangle2D frame = new RoundRectangle2D.Float(bounds.x, bounds.y, bounds.width, bounds.height, 6, 6);
+
+        Paint paint = new GradientPaint(0, 0, MAIN_GRADIENT_TOP, 0, getHeight(), getBackground());
+        graphics.setPaint(paint);
+        graphics.fill(frame);
+        
+        paint = new GradientPaint(0, 0, MAIN_BORDER_COLOR, 0, getHeight(), getBackground());
+        graphics.setPaint(paint);
+        frame = new RoundRectangle2D.Float(bounds.x, bounds.y, bounds.width -1, bounds.height, 6, 6);
+        graphics.draw(frame);
+    }
+    
+    /**
+     * paint the track sorrounding the main bar
+     */
+    protected void paintMainBarTrackFill(Graphics2D graphics, Rectangle bounds) {
+        
+        Paint paint = new GradientPaint(0, 0, MAIN_GRADIENT_TOP, 0, bounds.height, Color.WHITE);
+        graphics.setPaint(paint);
+        RoundRectangle2D frame = new RoundRectangle2D.Float(0, 0, bounds.width, bounds.height, 6, 6);
+        graphics.fill(frame);
+    }
+    
+    /**
+     */
+    protected void paintMainBarTrackBorder(Graphics2D graphics, Rectangle bounds) {
+        Paint paint = new GradientPaint(0, 0, MAIN_BORDER_COLOR, getWidth(), 0, getBackground());
+        graphics.setPaint(paint);
+        
+        RoundRectangle2D frame = new RoundRectangle2D.Float(0, 0, bounds.width - 1, bounds.height, 6, 6);
+        graphics.draw(frame);
+    }
+
+    
+    /**
+     * this is the main bar, will it up to what is defined by the model
+     */
+    protected void paintMainBarFill(Graphics2D graphics, Rectangle bounds) {
+        Paint paint = new GradientPaint(0, 0, MAIN_BAR_BASE_COLOR, getWidth() * 2, 0, getBackground());
+        graphics.setPaint(paint);
+        
+        RoundRectangle2D frame =
+                new RoundRectangle2D.Float(0, 0, getPrimaryModel().getValueNormalized(),
+                                           bounds.height, 6, 6);
+        graphics.fill(frame);
+        
+        String value = String.valueOf(getPrimaryModel().getValue()) + " " + primaryUnit;
+        Rectangle2D fontBounds = font.getStringBounds(value, graphics.getFontRenderContext());
+        int width = (int) (bounds.width/2 - fontBounds.getWidth()/2) - 1;
+        
+        if (width > getPrimaryModel().getValueNormalized()) {
+            graphics.setPaint(MAIN_BAR_BASE_COLOR);
+        } else {
+            graphics.setPaint(getBackground());
+        }
+
+        int height  = (int) (bounds.height / 2 + fontBounds.getHeight()/2);
+        SwingUtilities2.drawString(this, graphics, value, width, height);
+    }
+    
+    /**
+     */
+    private void paintMainBar(Graphics2D g, Rectangle bounds) {
+        
+        Graphics2D graphics = (Graphics2D) g.create();
+                
+        graphics.translate(bounds.x, bounds.y);
+        paintMainBarTrackFill(graphics, bounds);
+        
+        paintMainBarFill(graphics, bounds);
+        
+        paintMainBarTrackBorder(graphics, bounds);
+        graphics.dispose();
+    }
+    
+    /**
+     */
+    protected void drawBottomBar(Graphics2D g, Rectangle bounds) {
+
+        Graphics2D graphics = (Graphics2D) g.create();
+        graphics.translate(bounds.x, bounds.y + bounds.height);
+        
+        drawTickMark(graphics, bounds);
+        
+        paintSecondaryBarFill(graphics, bounds);
+        
+        graphics.dispose();
+    }
+    
+    /**
+     */
+    protected void drawTickMark(Graphics2D graphics, Rectangle bounds) {
+      
+        graphics.setPaint(MAIN_BORDER_COLOR);
+        
+        int smallTop = bounds.height - 5;
+        int smallBottom = bounds.height;
+
+        int mainTop = smallTop + 20;
+        int mainBottom = smallBottom - 15;
+      
+        // the first and last tick are always big, this is the first
+        graphics.drawLine(0, mainTop, 0, mainBottom);
+      
+        // the space between the vertical lines
+        double tickSpace = ((double) bounds.width) / TICK_NUM;
+      
+        internalSecondaryModel.setMaxNormalized(bounds.width);      
+        int numTicks = 0;
+
+        for (int x = 0; x < bounds.width; x += tickSpace + 0.5) {
+            if (numTicks % SMALL_TICK_NUM == 0) {
+              
+                graphics.drawLine(x, smallTop, x, smallBottom + 5);
+
+                internalSecondaryModel.setValue(x);
+            } else {
+                graphics.drawLine(x, smallTop, x, smallBottom);
+            }
+            numTicks++;
+        }
+        
+        // that's the last
+        graphics.drawLine(bounds.width, mainTop, bounds.width, mainBottom);
+        graphics.drawLine(0, smallTop, bounds.width, smallTop);
+        
+        drawStrings(graphics, mainBottom, mainTop, bounds.width);
+    }
+    
+    protected void drawStrings(Graphics2D graphics, int top, int bottom, int right) {
+      
+      // now draw the min/max values of both side of markers      
+      // top bar min value
+      FontMetrics fm = SwingUtilities2.getFontMetrics(this, font);
+      
+      String value = String.valueOf(getPrimaryModel().getMinimum()) + " " + primaryUnit;
+      int height = top + fm.getAscent()/2;
+      SwingUtilities2.drawString(this, graphics, value, 1, height);
+      
+      value = String.valueOf(getSecondaryModel().getMinimum()) + " " + secondaryUnit;
+      height = bottom;
+      SwingUtilities2.drawString(this, graphics, value, 1, height);
+      
+      value = String.valueOf(getPrimaryModel().getMaximum()) + " " + primaryUnit;
+      height = top + fm.getAscent()/2;
+
+      int width = (int) (right - font.getStringBounds(value, graphics.getFontRenderContext()).getWidth()) - 1;
+      SwingUtilities2.drawString(this, graphics, value, width, height);
+      
+      value = String.valueOf(getSecondaryModel().getMaximum()) + " " + secondaryUnit;
+      height = bottom;
+      width = (int) (right - font.getStringBounds(value, graphics.getFontRenderContext()).getWidth()) - 1;
+      SwingUtilities2.drawString(this, graphics, value, width, height);
+      
+      // now draw the actual value for the bottom bar, the top bar is drawn in
+      // its fill method
+      value = String.valueOf(getSecondaryModel().getValue()) + " " + secondaryUnit;
+      width = right/2;
+      Rectangle2D bounds = font.getStringBounds(value, graphics.getFontRenderContext());
+      width = (int) (width - bounds.getWidth()/2) - 1;
+      SwingUtilities2.drawString(this, graphics, value, width, height);
+      RoundRectangle2D frame = new RoundRectangle2D.Double(width - 2, height - bounds.getHeight(),
+                                                          bounds.getWidth() + 4, bounds.getHeight() + 4,
+                                                          4, 4);
+      graphics.draw(frame);
+    }
+    
+    protected void paintSecondaryBarFill(Graphics2D graphics, Rectangle bounds) {
+        
+        graphics.setPaint(MAIN_BAR_BASE_COLOR_TOP);
+        graphics.drawLine(1, bounds.height, getSecondaryModel().getValueNormalized() - 1, bounds.height);
+        
+        graphics.setPaint(MAIN_BAR_BASE_COLOR);
+        graphics.fillRect(1, bounds.height + 1, getSecondaryModel().getValueNormalized(), 2);
+    }
+    
+    protected void paintStats(Graphics2D graphics, Rectangle bounds) {
+        
+        int imageWidth = bounds.width - 2;
+        if (imageWidth < 0 || bounds.height < 0) {
+            return;
+        }
+        
+        StatsModel stats = getStats();
+        drawStats(graphics, stats, bounds.x, bounds.y, imageWidth, bounds.height);
+    }
+    
+    private void drawStats(Graphics2D graphics, StatsModel stats, int x, int y, int imageWidth, int height) {
+        if (stats != null) {
+            BufferedImage image = stats.getChart(imageWidth, height, STATS_BG,
+                                                 new ColorUIResource(getForeground()));
+       
+            paintStatsLabel(graphics, image, stats.getName());
+            graphics.drawImage(image, x, y, null);
+        }
+    }
+    
+    protected void paintStatsLabel(Graphics2D graphics, BufferedImage image, String label) {
+        int height = SwingUtilities2.getFontMetrics(this, font).getAscent() + 2;
+        if (height <= 0) {
+            return;
+        }
+        
+        Graphics2D imageGraphics = (Graphics2D) image.getGraphics();
+        imageGraphics.setColor(getForeground());
+        imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        
+        SwingUtilities2.drawString(this, imageGraphics, label, 2, height);
+    }
+    
+    @Override
+    protected void paintComponent(Graphics g) {
+
+        Graphics2D graphics = (Graphics2D) g.create();
+        graphics.setFont(font);
+        
+        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+        
+        Rectangle outerBounds = getOuterBounds();
+        Rectangle innerBounds = getBoundsWithInsets(outerBounds);
+        Rectangle statsBound =  getBoundsWithInsets(outerBounds);
+        
+        // move the bar close to the center
+        innerBounds.height = MAIN_BAR_HEIGHT;
+        innerBounds.y = outerBounds.height/2;
+        
+        // make the stats area cover the upper portion instead
+        statsBound.height = (outerBounds.height/2) - MAIN_BAR_HEIGHT;
+        
+        resetModels(0, innerBounds.width);
+
+        // some eye candy
+        paintOuterFrame(graphics, outerBounds);
+
+        // paint the usage stats
+        paintStats(graphics, statsBound);
+        
+        // main and bottom bars
+        paintMainBar(graphics, innerBounds);
+        drawBottomBar(graphics, innerBounds);
+        
+        graphics.dispose();
+    }
+    
+    private void resetModels(int min, int max) {
+        
+        getPrimaryModel().setMaxNormalized(max);
+        getPrimaryModel().setMinNormalized(min);
+        
+        RangeModel model = getSecondaryModel();
+        model.setMaxNormalized(max);
+        model.setMinNormalized(min);
+        
+        internalSecondaryModel.setMaximum(model.getMaximum());
+        internalSecondaryModel.setMinimum(model.getMinimum());
+        internalSecondaryModel.setValue(model.getValue());
+        
+        internalSecondaryModel.setMaxNormalized(max);
+        internalSecondaryModel.setMinNormalized(0);
+    }
+    
+    @Override
+    @Transient
+    public Dimension getPreferredSize() {
+        return new Dimension(850, 150);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/MemoryStatsController.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.core;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import com.redhat.thermostat.client.core.controllers.VmInformationServiceController;
+import com.redhat.thermostat.client.core.views.BasicView.Action;
+import com.redhat.thermostat.client.core.views.UIComponent;
+import com.redhat.thermostat.client.stats.memory.core.locale.LocaleResources;
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.NotImplementedException;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.Timer.SchedulingType;
+import com.redhat.thermostat.common.appctx.ApplicationContext;
+import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.locale.Translate;
+import com.redhat.thermostat.common.model.VmMemoryStat;
+import com.redhat.thermostat.common.model.VmMemoryStat.Generation;
+import com.redhat.thermostat.common.model.VmMemoryStat.Space;
+import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
+
+class MemoryStatsController implements VmInformationServiceController {
+
+    private final MemoryStatsView view;
+    private final VmMemoryStatDAO vmDao;
+   
+    private final VmRef ref;
+    private final Timer timer;
+    
+    private final Map<String, Payload> regions;
+    
+    private VMCollector collector;
+    
+    class VMCollector implements Runnable {
+
+        private long desiredUpdateTimeStamp = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1);
+
+        @Override
+        public void run() {
+            List<VmMemoryStat> vmInfo = vmDao.getLatestVmMemoryStats(ref, desiredUpdateTimeStamp);
+            for (VmMemoryStat memoryStats: vmInfo) {
+                List<Generation> generations = memoryStats.getGenerations();
+                
+                for (Generation generation : generations) {
+                    List<Space> spaces = generation.spaces;
+                    for (Space space: spaces) {
+                        Payload payload = regions.get(space.name);
+                        if (payload == null) {
+                            payload = new Payload();
+                            payload.setName(space.name);
+                        }
+
+                        Scale usedScale = normalizeScale(space.used, space.capacity);
+                        double used = Scale.convertTo(usedScale, space.used, 100);
+                        double maxUsed = Scale.convertTo(usedScale, space.capacity, 100);
+                        
+                        payload.setUsed(used);
+                        payload.setMaxUsed(maxUsed);
+                        payload.setUsedUnit(usedScale);
+                        
+                        Scale maxScale = normalizeScale(space.capacity, space.maxCapacity);
+                        double capacity = Scale.convertTo(maxScale, space.capacity, 100);
+                        double maxCapacity = Scale.convertTo(maxScale, space.maxCapacity, 100);
+                        
+                        payload.setCapacity(capacity);
+                        payload.setMaxCapacity(maxCapacity);
+                        payload.setCapacityUnit(maxScale);
+                        
+                        String tooltip = space.name + ": used: " + used + " " + usedScale +
+                                ", capacity: " + capacity + " " + maxScale +
+                                ", max capacity: " + maxCapacity + " " + maxScale;
+                        
+                        payload.setTooltip(tooltip);
+                        
+                        StatsModel model = payload.getModel();
+                        if (model == null) {
+                            model = new StatsModel();
+                            model.setName(space.name);
+                            model.setRange(3600);
+                        }
+                        
+                        // normalize this always in the same unit
+                        model.addData(memoryStats.getTimeStamp(),
+                                      Scale.convertTo(Scale.MiB, space.used, 100));
+                        
+                        payload.setModel(model);
+                        if (regions.containsKey(space.name)) {
+                            view.updateRegion(payload.clone());
+                        } else {
+                            view.addRegion(payload.clone());
+                            regions.put(space.name, payload);
+                        }
+                        
+                        view.requestRepaint();
+                        desiredUpdateTimeStamp = Math.max(desiredUpdateTimeStamp, memoryStats.getTimeStamp());
+                    }
+                }
+            }
+        }
+    }
+    
+    public MemoryStatsController(final VmMemoryStatDAO vmMemoryStatDao, final VmRef ref, MemoryStatsViewProvider viewProvider) {
+        
+        regions = new HashMap<>();
+        this.ref = ref;
+        vmDao = vmMemoryStatDao;
+        view = viewProvider.createView();
+        
+        timer = ApplicationContext.getInstance().getTimerFactory().createTimer();
+        
+        collector = new VMCollector();
+        timer.setAction(collector);
+        
+        timer.setInitialDelay(0);
+        timer.setDelay(1000);
+        timer.setTimeUnit(TimeUnit.MILLISECONDS);
+        timer.setSchedulingType(SchedulingType.FIXED_RATE);
+
+        view.addActionListener(new ActionListener<Action>() {
+            @Override
+            public void actionPerformed(ActionEvent<Action> actionEvent) {
+                switch(actionEvent.getActionId()) {
+                    case HIDDEN:
+                        stop();
+                        break;
+                        
+                    case VISIBLE:
+                        start();
+                        break;
+                        
+                    default:
+                        throw new NotImplementedException("unknown event: " + actionEvent.getActionId());
+                }
+            }
+        });
+    }
+    
+    // for testing
+    VMCollector getCollector() {
+        return collector;
+    };
+    
+    Map<String, Payload> getRegions() {
+        return regions;
+    }
+    
+    private Scale normalizeScale(long min, long max) {
+        // FIXME: this is very dumb and very inefficient
+        // needs cleanup
+        Scale minScale = Scale.getScale(min);
+        Scale maxScale = Scale.getScale(max);
+        
+        Scale[] scales = Scale.values();
+        int maxID = 0;
+        int minID = 0;
+        for (int i = 0; i < scales.length; i++) {
+            if (scales[i] == minScale) {
+                minID = i;
+            }
+            if (scales[i] == maxScale) {
+                maxID = i;
+            }
+        }
+        while (maxID - minID >= 2) {
+            minID++;
+        }
+        return scales[minID];
+    }
+    
+    private void start() {
+        timer.start();
+    }
+
+    private void stop() {
+        timer.stop();
+    }
+
+    @Override
+    public String getLocalizedName() {
+        Translate<LocaleResources> t = LocaleResources.createLocalizer();
+        return t.localize(LocaleResources.VM_INFO_TAB_MEMORY);
+    }
+
+    @Override
+    public UIComponent getView() {
+        return (UIComponent) view;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/MemoryStatsService.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.core;
+
+import com.redhat.thermostat.client.core.VmFilter;
+import com.redhat.thermostat.client.core.VmInformationService;
+import com.redhat.thermostat.client.core.controllers.VmInformationServiceController;
+import com.redhat.thermostat.client.osgi.service.AlwaysMatchFilter;
+import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.utils.OSGIUtils;
+
+public class MemoryStatsService implements VmInformationService {
+    
+    private VmFilter filter = new AlwaysMatchFilter();
+
+    private VmMemoryStatDAO vmMemoryStatDao;
+
+    public MemoryStatsService(VmMemoryStatDAO vmMemoryStatDao) {
+        this.vmMemoryStatDao = vmMemoryStatDao;
+    }
+    
+    @Override
+    public VmInformationServiceController getInformationServiceController(VmRef ref) {
+        MemoryStatsViewProvider viewProvider = OSGIUtils.getInstance().getService(MemoryStatsViewProvider.class);
+        return new MemoryStatsController(vmMemoryStatDao, ref, viewProvider);
+    }
+
+    @Override
+    public VmFilter getFilter() {
+        return filter;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/MemoryStatsView.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.core;
+
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.core.views.UIComponent;
+
+public abstract class MemoryStatsView extends BasicView implements UIComponent {
+    
+    public abstract void addRegion(Payload region);
+    public abstract void updateRegion(Payload region);
+    
+    public abstract void requestRepaint();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/MemoryStatsViewProvider.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.core;
+
+import com.redhat.thermostat.client.core.views.ViewProvider;
+
+public interface MemoryStatsViewProvider extends ViewProvider {
+
+    @Override
+    public MemoryStatsView createView();
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/Payload.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.core;
+
+import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
+
+public class Payload implements Cloneable {
+
+    private String name;
+    private String tooltip;
+    
+    private double capacity;
+    private double maxCapacity;
+    private double maxUsed;
+    private double used;
+    
+    private Scale usedUnit;
+    private Scale capacityUnit;
+    
+    private StatsModel model;
+    
+    public void setModel(StatsModel model) {
+        this.model = model;
+    }
+    
+    public StatsModel getModel() {
+        return model;
+    }
+    
+    public void setCapacityUnit(Scale capacityUnit) {
+        this.capacityUnit = capacityUnit;
+    }
+    
+    public Scale getCapacityUnit() {
+        return capacityUnit;
+    }
+    
+    public void setUsedUnit(Scale usedUnit) {
+        this.usedUnit = usedUnit;
+    }
+    
+    public Scale getUsedUnit() {
+        return usedUnit;
+    }
+    
+    public double getMaxCapacity() {
+        return maxCapacity;
+    }
+    
+    public void setMaxCapacity(double maxCapacity) {
+        this.maxCapacity = maxCapacity;
+    }
+    
+    public double getUsed() {
+        return used;
+    }
+    
+    public void setUsed(double used) {
+        this.used = used;
+    }
+    
+    public double getMaxUsed() {
+        return maxUsed;
+    }
+    
+    public void setMaxUsed(double maxUsed) {
+        this.maxUsed = maxUsed;
+    }
+    
+    public double getCapacity() {
+        return capacity;
+    }
+    
+    public void setCapacity(double capacity) {
+        this.capacity = capacity;
+    }
+    
+    public String getName() {
+        return name;
+    }
+    
+    public void setName(String name) {
+        this.name = name;
+    }
+    
+    public String getTooltip() {
+        return tooltip;
+    }
+    
+    public void setTooltip(String tooltip) {
+        this.tooltip = tooltip;
+    }
+    
+    @Override
+    protected Payload clone() {
+        
+        Payload copy = new Payload();
+        
+        copy.used = used;
+        copy.capacity = capacity;
+        copy.capacityUnit = capacityUnit;
+        copy.maxCapacity = maxCapacity;
+        copy.maxUsed = maxUsed;
+        copy.model = model.clone();
+        copy.name = name;
+        copy.tooltip = tooltip;
+        copy.usedUnit = usedUnit;
+        
+        return copy;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/RangeModel.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.core;
+
+public class RangeModel {
+
+    private int minNormalized;
+    private double min;
+    
+    private int maxNormalized;
+    private double max;
+ 
+    private double value;
+ 
+    public double getMinimum() {
+        return min;
+    }
+
+    public void setMinimum(double newMinimum) {
+        this.min = newMinimum;
+    }
+
+    public double getMaximum() {
+        return max;
+    }
+
+    public void setMaximum(double newMaximum) {
+        this.max = newMaximum;
+    }
+
+    public void setMaxNormalized(int maxNormalized) {
+        this.maxNormalized = maxNormalized;
+    }
+    
+    public void setMinNormalized(int minNormalized) {
+        this.minNormalized = minNormalized;
+    }
+    
+    public double getValue() {
+        return value;
+    }
+
+    public void setValue(double newValue) {
+        this.value = newValue;
+    }
+    
+    int getMaxNormalized() {
+        return maxNormalized;
+    }
+    
+    int getMinNormalized() {
+        return minNormalized;
+    }
+    
+    public int getValueNormalized() {
+        double normalized = ((value - min) * (maxNormalized - minNormalized)/(max - min)) + minNormalized;
+        return (int) Math.round(normalized);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/StatsModel.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.core;
+
+import java.awt.Graphics2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.util.Date;
+
+import javax.swing.plaf.ColorUIResource;
+
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.DateAxis;
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
+import org.jfree.data.time.Millisecond;
+import org.jfree.data.time.TimeSeries;
+import org.jfree.data.time.TimeSeriesCollection;
+import org.jfree.data.xy.XYDataset;
+import org.jfree.ui.RectangleInsets;
+
+public class StatsModel implements Cloneable {
+
+    private static final String lock = new String("MemoryStatsModelLock");
+
+    private String name;
+    
+    private TimeSeries dataSet;
+    
+    public StatsModel() {
+        dataSet = new TimeSeries("");
+    }
+    
+    BufferedImage getChart(int width, int height, ColorUIResource bgColor, ColorUIResource fgColor) {
+        JFreeChart chart = createChart(bgColor, fgColor);
+        
+        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+        chart.draw((Graphics2D) image.getGraphics(), new Rectangle2D.Double(0, 0, width, height), null);
+        
+        return image;
+    }
+    
+    public String getName() {
+        return name;
+    }
+    
+    public void setName(String name) {
+        dataSet.setDescription(name);
+        this.name = name;
+    }
+    
+    public void setRange(int seconds) {
+        dataSet.setMaximumItemCount(seconds);
+    }
+    
+    public void addData(long timestamp, double value) {
+        Millisecond millisecond = new Millisecond(new Date(timestamp));
+        synchronized (lock) {
+            if (dataSet.getValue(millisecond) == null) {
+                dataSet.add(millisecond, value);
+                dataSet.removeAgedItems(true);
+            }
+        }
+    }
+    
+    @Override
+    protected StatsModel clone() {
+        
+        StatsModel model = new StatsModel();
+        model.setName(name);
+        model.setRange(dataSet.getMaximumItemCount());
+        
+        try {
+            model.dataSet = dataSet.createCopy(0, dataSet.getItemCount() - 1);
+        } catch (CloneNotSupportedException e) {
+            // ah... it's supported here...
+            e.printStackTrace();
+        }
+        
+        return model;
+    }
+    
+    /**
+     * Creates a chart.
+     *
+     * @return a chart.
+     */
+    private JFreeChart createChart(ColorUIResource bgColor, ColorUIResource fgColor) {
+
+        XYDataset priceData = null;
+        synchronized (lock) {            
+            try {
+                priceData = new TimeSeriesCollection(dataSet.createCopy(0,
+                                                     dataSet.getItemCount() - 1));
+            } catch (CloneNotSupportedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        XYPlot plot = new XYPlot();
+        
+        plot.setDomainGridlinesVisible(false);
+        plot.setDomainCrosshairVisible(false);
+        plot.setRangeGridlinesVisible(false);
+        plot.setRangeCrosshairVisible(false);
+                
+        DateAxis dateAxis = new DateAxis();
+        
+        dateAxis.setTickLabelsVisible(false);
+        dateAxis.setTickMarksVisible(false);
+        dateAxis.setAxisLineVisible(false);
+        dateAxis.setNegativeArrowVisible(false);
+        dateAxis.setPositiveArrowVisible(false);
+        dateAxis.setVisible(false);
+        
+        NumberAxis numberAxis = new NumberAxis();
+        numberAxis.setTickLabelsVisible(false);
+        numberAxis.setTickMarksVisible(false);
+        numberAxis.setAxisLineVisible(false);
+        numberAxis.setNegativeArrowVisible(false);
+        numberAxis.setPositiveArrowVisible(false);
+        numberAxis.setVisible(false);
+        numberAxis.setAutoRangeIncludesZero(false);
+        
+        plot.setDomainAxis(dateAxis);
+        plot.setRangeAxis(numberAxis);
+        plot.setDataset(priceData);
+        
+        plot.setInsets(new RectangleInsets(-1, -1, 0, 0));
+        
+        plot.setRenderer(new StandardXYItemRenderer(StandardXYItemRenderer.LINES));
+        plot.setBackgroundPaint(bgColor);
+        
+        JFreeChart chart = new JFreeChart(null, JFreeChart.DEFAULT_TITLE_FONT, plot, false);
+        
+        plot.getRenderer().setSeriesPaint(0, fgColor);
+        chart.setAntiAlias(true);
+        chart.setBorderVisible(false);
+        
+        return chart;
+    }
+    
+    TimeSeries getDataSet() {
+        return dataSet;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/java/com/redhat/thermostat/client/stats/memory/core/locale/LocaleResources.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.core.locale;
+
+import com.redhat.thermostat.common.locale.Translate;
+
+public enum LocaleResources {
+
+    VM_INFO_TAB_MEMORY,
+    RESOURCE_MISSING;
+    
+    public static final String RESOURCE_BUNDLE =
+            "com.redhat.thermostat.client.stats.memory.locale.strings";
+    
+    public static Translate<LocaleResources> createLocalizer() {
+        return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/main/resources/com/redhat/thermostat/client/stats/memory/locale/strings.properties	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,2 @@
+RESOURCE_MISSING = Missing translation!
+VM_INFO_TAB_MEMORY = Memory
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/test/java/com/redhat/thermostat/client/stats/memory/core/MemoryStatsControllerTest.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.core;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import com.redhat.thermostat.common.ActionEvent;
+import com.redhat.thermostat.common.ActionListener;
+import com.redhat.thermostat.common.Timer;
+import com.redhat.thermostat.common.Timer.SchedulingType;
+import com.redhat.thermostat.common.TimerFactory;
+import com.redhat.thermostat.common.appctx.ApplicationContext;
+import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
+import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
+import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.model.VmMemoryStat;
+import com.redhat.thermostat.common.model.VmMemoryStat.Generation;
+import com.redhat.thermostat.common.model.VmMemoryStat.Space;
+
+public class MemoryStatsControllerTest {
+
+    private List<Generation> generations = new ArrayList<>();
+    
+    private VmMemoryStatDAO memoryStatDao;
+    private MemoryStatsView view;
+    private Timer timer;
+    
+    private ActionListener<MemoryStatsView.Action> viewListener;
+    
+    private MemoryStatsController controller;
+    
+    private Space canary;
+
+    
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Before
+    public void setUp() {
+        timer = mock(Timer.class);
+        ArgumentCaptor<Runnable> actionCaptor = ArgumentCaptor.forClass(Runnable.class);
+        doNothing().when(timer).setAction(actionCaptor.capture());
+        
+        TimerFactory timerFactory = mock(TimerFactory.class);
+        when(timerFactory.createTimer()).thenReturn(timer);
+        ApplicationContext.getInstance().setTimerFactory(timerFactory);
+        
+        List<VmMemoryStat> vmInfo = new ArrayList<>();
+        
+        for (int i = 0; i < 2; i++) {
+            Generation generation = new Generation();
+            generation.name = "fluff" + i;
+            generation.spaces = new ArrayList<>();
+            for (int j = 0; j < 2; j++) {
+                Space space = new Space();
+                space.name = "fluffer" + i + j;
+                space.used = 100;
+                space.capacity = 1000;
+                space.maxCapacity = 10000;
+                
+                generation.spaces.add(space);
+            }
+            generations.add(generation);
+        }
+        
+        // special payload because the others have all the same values
+        canary = new Space();
+        canary.name = "canary";
+        canary.used = 1;
+        canary.capacity = 2;
+        canary.maxCapacity = 3;
+        
+        long timestamp = 1;
+        int vmID = 1;
+        for (int i = 0; i < 5; i++) {
+            VmMemoryStat vmMemory = new VmMemoryStat(timestamp++, vmID, generations);
+            vmInfo.add(vmMemory);
+        }
+        
+        generations.get(0).spaces.add(canary);
+        
+        memoryStatDao = mock(VmMemoryStatDAO.class);
+        when(memoryStatDao.getLatestVmMemoryStats(any(VmRef.class), anyLong())).thenReturn(vmInfo);
+        
+        view = mock(MemoryStatsView.class);
+        MemoryStatsViewProvider viewProvider = mock(MemoryStatsViewProvider.class);
+        when(viewProvider.createView()).thenReturn(view);
+        
+        ArgumentCaptor<ActionListener> viewArgumentCaptor =
+                ArgumentCaptor.forClass(ActionListener.class);
+        doNothing().when(view).addActionListener(viewArgumentCaptor.capture());
+
+        VmRef ref = mock(VmRef.class);
+        
+        controller = new MemoryStatsController(memoryStatDao, ref, viewProvider);
+        
+        viewListener = viewArgumentCaptor.getValue();
+    }
+    
+    @Test
+    public void testStartStopTimer() {
+        viewListener.actionPerformed(new ActionEvent<>(view, MemoryStatsView.Action.VISIBLE));
+
+        verify(timer).start();
+        verify(timer).setSchedulingType(SchedulingType.FIXED_RATE);
+
+        viewListener.actionPerformed(new ActionEvent<>(view, MemoryStatsView.Action.HIDDEN));
+
+        verify(timer).stop();
+    }
+
+    @Test
+    public void testPayloadContainSpaces() {
+        MemoryStatsController.VMCollector collettor = controller.getCollector();
+        collettor.run();
+        
+        Map<String, Payload> regions = controller.getRegions();
+        assertEquals(5, regions.size());
+        
+        assertTrue(regions.containsKey("fluffer00"));
+        assertTrue(regions.containsKey("fluffer01"));
+        assertTrue(regions.containsKey("fluffer10"));
+        assertTrue(regions.containsKey("fluffer11"));
+        
+        assertTrue(regions.containsKey("canary"));
+    }
+    
+    @Test
+    public void testValues() {
+        MemoryStatsController.VMCollector collettor = controller.getCollector();
+        collettor.run();
+        
+        Map<String, Payload> regions = controller.getRegions();
+
+        Payload payload = regions.get("fluffer00");
+        assertEquals("fluffer00", payload.getName());
+        assertEquals(10000, payload.getMaxCapacity(), 0);
+        assertEquals(1000, payload.getCapacity(), 0);
+        assertEquals(100, payload.getUsed(), 0);
+        
+        payload = regions.get("canary");
+        assertEquals("canary", payload.getName());
+        assertEquals(3, payload.getMaxCapacity(), 0);
+        assertEquals(2, payload.getCapacity(), 0);
+        assertEquals(1, payload.getUsed(), 0);
+        
+        // the value above all ensure the same scale is used
+        String tooltip = payload.getName() + ": used: " + payload.getUsed() + " " +
+                         payload.getUsedUnit() + ", capacity: " +
+                         payload.getCapacity() + " " + payload.getUsedUnit() +
+                         ", max capacity: " + payload.getMaxCapacity() + " " +
+                         payload.getUsedUnit();
+        
+        assertEquals(tooltip, payload.getTooltip());
+    }
+    
+
+    @Test
+    public void testTimerFetchesMemoryDataDeltaOnly() {
+        ArgumentCaptor<Long> timeStampCaptor = ArgumentCaptor.forClass(Long.class);
+
+        final long DATA_TIMESTAMP = System.currentTimeMillis() + 1000000000;
+        Space space = new Space();
+        space.capacity = 10;
+        space.maxCapacity = 20;
+        space.used = 5;
+        Generation gen = new Generation();
+        gen.name = "foobar";
+        gen.spaces = Arrays.asList(space);
+        VmMemoryStat stat = new VmMemoryStat();
+        stat.setTimeStamp(DATA_TIMESTAMP);
+        stat.setGenerations(Arrays.asList(gen));
+
+        when(memoryStatDao.getLatestVmMemoryStats(isA(VmRef.class), anyLong())).thenReturn(Arrays.asList(stat));
+
+        Runnable timerAction = controller.getCollector();
+
+        timerAction.run();
+        timerAction.run();
+
+        verify(memoryStatDao, times(2)).getLatestVmMemoryStats(isA(VmRef.class), timeStampCaptor.capture());
+
+        long timeStamp1 = timeStampCaptor.getAllValues().get(0);
+        assertTimeStampIsAround(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1), timeStamp1);
+
+        long timeStamp2 = timeStampCaptor.getAllValues().get(1);
+        assertTimeStampIsAround(DATA_TIMESTAMP, timeStamp2);
+    }
+
+    @Test
+    public void testTimerFetchesMemoryDataDeltaOnlyEvenWithNoData() {
+        ArgumentCaptor<Long> timeStampCaptor = ArgumentCaptor.forClass(Long.class);
+
+        Runnable timerAction = controller.getCollector();
+
+        timerAction.run();
+        timerAction.run();
+
+        verify(memoryStatDao, times(2)).getLatestVmMemoryStats(isA(VmRef.class), timeStampCaptor.capture());
+
+        long timeStamp1 = timeStampCaptor.getAllValues().get(0);
+        assertTimeStampIsAround(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1), timeStamp1);
+
+        long timeStamp2 = timeStampCaptor.getAllValues().get(1);
+        assertTimeStampIsAround(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1), timeStamp2);
+    }
+
+    private void assertTimeStampIsAround(long expected, long actual) {
+        assertTrue(actual <= expected + 1000);
+        assertTrue(actual >= expected - 1000);
+    }
+
+    @After
+    public void tearDown() {
+        ApplicationContextUtil.resetApplicationContext();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/test/java/com/redhat/thermostat/client/stats/memory/core/PayloadTest.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.core;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
+
+public class PayloadTest {
+
+    @Test
+    public void testClone() {
+        
+        StatsModel model = new StatsModel();
+        model.setName("fluffModel");
+        model.setRange(100);
+        model.addData(500, 2.0);
+        model.addData(501, 2.1);
+        
+        Payload source = new Payload();
+        source.setCapacity(10.0);
+        source.setName("fluff");
+        source.setCapacityUnit(Scale.GiB);
+        source.setMaxCapacity(100.0);
+        source.setMaxUsed(5.0);
+        source.setUsed(3.0);
+        source.setUsedUnit(Scale.MiB);
+        source.setModel(model);
+        source.setTooltip("fluffTooltip");
+        
+        Payload cloned = source.clone();
+        assertNotSame(cloned, source);
+        
+        assertEquals(source.getName(), cloned.getName());
+        assertEquals(source.getCapacity(), cloned.getCapacity(), 0);
+        assertEquals(source.getCapacityUnit(), cloned.getCapacityUnit());
+        assertEquals(source.getMaxCapacity(), cloned.getMaxCapacity(), 0);
+        assertEquals(source.getMaxUsed(), cloned.getMaxUsed(), 0);
+        assertEquals(source.getTooltip(), cloned.getTooltip());
+        assertEquals(source.getUsed(), cloned.getUsed(), 0);
+        assertEquals(source.getUsedUnit(), cloned.getUsedUnit());
+        assertNotSame(source.getModel(), cloned.getModel());
+
+        assertEquals(source.getModel().getName(), cloned.getModel().getName());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/test/java/com/redhat/thermostat/client/stats/memory/core/RangeModelTest.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.core;
+
+import static org.junit.Assert.*;
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+public class RangeModelTest {
+
+    @Test
+    public void testSameRange() {
+        RangeModel model = new RangeModel();
+        
+        model.setMaximum(10);
+        model.setMinimum(0);
+        model.setValue(5);
+        
+        model.setMaxNormalized(10);
+        model.setMinNormalized(0);
+        
+        
+        Assert.assertEquals((int) model.getValue(), model.getValueNormalized());
+    }
+
+    @Test
+    public void testDoubleRange() {
+        RangeModel model = new RangeModel();
+        
+        model.setMaximum(10);
+        model.setMinimum(0);
+        model.setValue(5);
+        
+        model.setMaxNormalized(20);
+        model.setMinNormalized(0);
+        
+        
+        Assert.assertEquals(10, model.getValueNormalized());
+    }
+    
+    @Test
+    public void testRanges() {
+        RangeModel model = new RangeModel();
+        
+        model.setMaximum(10);
+        model.setMinimum(0);
+        model.setValue(5);
+        
+        model.setMaxNormalized(40);
+        model.setMinNormalized(0);
+                
+        Assert.assertEquals(20, model.getValueNormalized());
+        
+        model.setMaxNormalized(60);
+        model.setMinNormalized(0);
+                
+        Assert.assertEquals(30, model.getValueNormalized());
+                
+        model.setMaxNormalized(200);
+        model.setMinNormalized(100);
+                
+        Assert.assertEquals(150, model.getValueNormalized());
+        
+        model.setMaximum(100);
+        model.setMinimum(0);
+        model.setValue(50);
+        
+        model.setMaxNormalized(1);
+        model.setMinNormalized(0);
+                
+        Assert.assertEquals(1, model.getValueNormalized());
+        
+        model.setValue(49);
+        Assert.assertEquals(0, model.getValueNormalized());
+        
+        model.setMaximum(1.0);
+        model.setMinimum(0.0);
+        model.setValue(0.5);
+        
+        model.setMaxNormalized(100);
+        model.setMinNormalized(0);
+        
+        Assert.assertEquals(50, model.getValueNormalized());
+        
+        model.setValue(0.72);
+        Assert.assertEquals(72, model.getValueNormalized());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/test/java/com/redhat/thermostat/client/stats/memory/core/StatsModelTest.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.core;
+
+import static org.junit.Assert.*;
+
+import org.jfree.data.time.TimeSeries;
+import org.junit.Test;
+
+public class StatsModelTest {
+
+    @Test
+    public void testClone() {
+        
+        StatsModel source = new StatsModel();
+        source.setName("fluffModel");
+        source.setRange(100);
+        source.addData(500, 2.0);
+        source.addData(501, 2.1);
+        
+        StatsModel cloned = source.clone();
+        
+        assertNotSame(cloned, source);
+        
+        assertEquals(source.getName(), cloned.getName());
+     
+        assertNotSame(cloned.getDataSet(), source.getDataSet());
+        
+        for (Object series : cloned.getDataSet().getItems()) {
+            assertTrue(source.getDataSet().getItems().contains(series));
+        }
+        
+        assertEquals(cloned.getDataSet().getItemCount(),
+                     source.getDataSet().getItemCount());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/core/src/test/java/com/redhat/thermostat/client/stats/memory/core/locale/TranslateTest.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.core.locale;
+
+import java.io.IOException;
+import java.util.Locale;
+import java.util.Properties;
+
+import junit.framework.Assert;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.client.stats.memory.core.locale.LocaleResources;
+import com.redhat.thermostat.common.locale.Translate;
+
+public class TranslateTest {
+
+    private Locale lang;
+
+    @Before
+    public void setUp() {
+        this.lang = Locale.getDefault();
+        Locale.setDefault(Locale.US);
+    }
+
+    @After
+    public void tearDown() {
+        Locale.setDefault(lang);
+    }
+
+    @Test
+    public void verifyTranslationsAreThere() throws IOException {
+
+        String stringsResource = "/" + LocaleResources.RESOURCE_BUNDLE.replace(".", "/") + ".properties";
+
+        Properties props = new Properties();
+        props.load(getClass().getResourceAsStream(stringsResource));
+
+        Assert.assertEquals(LocaleResources.values().length, props.values().size());
+        Translate<LocaleResources> t = LocaleResources.createLocalizer();
+        Assert.assertEquals("Missing translation!", t.localize(LocaleResources.RESOURCE_MISSING));
+        Assert.assertEquals("Memory", t.localize(LocaleResources.VM_INFO_TAB_MEMORY));
+    }
+}
--- a/client/memory-stats-panel/pom.xml	Tue Oct 23 11:21:50 2012 -0400
+++ b/client/memory-stats-panel/pom.xml	Tue Oct 23 11:22:31 2012 -0400
@@ -1,81 +1,58 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+
+ Copyright 2012 Red Hat, Inc.
+
+ This file is part of Thermostat.
+
+ Thermostat is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ Thermostat is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Thermostat; see the file COPYING.  If not see
+ <http://www.gnu.org/licenses />.
+
+ Linking this code with other modules is making a combined work
+ based on this code.  Thus, the terms and conditions of the GNU
+ General Public License cover the whole combination.
+
+ As a special exception, the copyright holders of this code give
+ you permission to link this code with independent modules to
+ produce an executable, regardless of the license terms of these
+ independent modules, and to copy and distribute the resulting
+ executable under terms of your choice, provided that you also
+ meet, for each linked independent module, the terms and conditions
+ of the license of that module.  An independent module is a module
+ which is not derived from or based on this code.  If you modify
+ this code, you may extend this exception to your version of the
+ library, but you are not obligated to do so.  If you do not wish
+ to do so, delete this exception statement from your version.
+
+-->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
+
   <parent>
+    <groupId>com.redhat.thermostat</groupId>
     <artifactId>thermostat-client</artifactId>
-    <groupId>com.redhat.thermostat</groupId>
     <version>0.5.0-SNAPSHOT</version>
   </parent>
+
   <artifactId>thermostat-osgi-memory-stats-panel</artifactId>
-  <packaging>bundle</packaging>
+  <packaging>pom</packaging>
+
   <name>Thermostat Client VM Memory Monitor plugin</name>
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <configuration>
-          <instructions>
-            <Private-Package>
-            	com.redhat.thermostat.client.stats.memory,
-         		com.redhat.thermostat.client.stats.memory.locale,
-            </Private-Package>
-            <Bundle-Activator>com.redhat.thermostat.client.stats.memory.MemoryStatsPanelActivator</Bundle-Activator>
-            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
-            <Bundle-SymbolicName>com.redhat.thermostat.client.stats.memory</Bundle-SymbolicName>
-            <!-- Do not autogenerate uses clauses in Manifests -->
-            <_nouses>true</_nouses>
-          </instructions>
-        </configuration>
-      </plugin>
-    </plugins>
-  </build>
-  <dependencies>
 
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.mockito</groupId>
-      <artifactId>mockito-core</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.easytesting</groupId>
-      <artifactId>fest-swing</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>net.java.openjdk.cacio</groupId>
-      <artifactId>cacio-tta</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.osgi</groupId>
-      <artifactId>org.osgi.core</artifactId>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.osgi</groupId>
-      <artifactId>org.osgi.compendium</artifactId>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.jfree</groupId>
-      <artifactId>jfreechart</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-common-core</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-client-core</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-  </dependencies>
+  <modules>
+    <module>core</module>
+    <module>swing</module>
+  </modules>
+
 </project>
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryGraphPanel.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-import java.awt.Dimension;
-import java.beans.Transient;
-
-import javax.swing.BoxLayout;
-import javax.swing.JPanel;
-
-@SuppressWarnings("serial")
-class MemoryGraphPanel extends JPanel {
-
-    private MemoryMeter meter;
-    
-    /**
-     * Create the panel.
-     */
-    public MemoryGraphPanel() {
-        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
-        meter = new MemoryMeter();
-        add(meter);
-    }
-    
-    public void setMemoryGraphProperties(Payload region) {
-
-        meter.getPrimaryModel().setMinimum(0);
-        meter.getPrimaryModel().setMaximum(region.getMaxUsed());
-        meter.getPrimaryModel().setValue(region.getUsed());
-        
-        meter.getSecondaryModel().setMinimum(0);
-        meter.getSecondaryModel().setMaximum(region.getMaxCapacity());
-        meter.getSecondaryModel().setValue(region.getCapacity());
-        
-        meter.setToolTipText(region.getTooltip());
-        
-        meter.setPrimaryScaleUnit(region.getUsedUnit().toString());
-        meter.setSecondayScaleUnit(region.getCapacityUnit().toString());
-        
-        meter.setStats(region.getModel());
-    }
-    
-    @Override
-    @Transient
-    public Dimension getPreferredSize() {
-        return meter.getPreferredSize();
-    }
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryMeter.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,433 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.FontMetrics;
-import java.awt.GradientPaint;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Insets;
-import java.awt.Paint;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.geom.Rectangle2D;
-import java.awt.geom.RoundRectangle2D;
-import java.awt.image.BufferedImage;
-import java.beans.Transient;
-
-import javax.swing.JComponent;
-import javax.swing.plaf.ColorUIResource;
-
-import sun.swing.SwingUtilities2;
-
-@SuppressWarnings({ "restriction", "serial" })
-public class MemoryMeter extends JComponent {
-    
-    // TODO the font should be customizable
-    private static final Font font = new Font("SansSerif", Font.PLAIN, 10);
-    
-    private static final int TICK_NUM = 100;
-    private static final int SMALL_TICK_NUM = 5;
-    
-    private static final int MAIN_BAR_HEIGHT = 20;
-    
-    private static final ColorUIResource MAIN_GRADIENT_TOP = new ColorUIResource(0xf1f3f1);
-    private static final ColorUIResource MAIN_BORDER_COLOR = new ColorUIResource(0xa8aca8);
-    
-    private static final ColorUIResource MAIN_BAR_BASE_COLOR_TOP = new ColorUIResource(0xbcd5ef);
-    private static final ColorUIResource MAIN_BAR_BASE_COLOR = new ColorUIResource(0x4A90D9);
-    
-    //private static final ColorUIResource STATS_BG = new ColorUIResource(0xF8F8F8);
-    private static final ColorUIResource STATS_BG = new ColorUIResource(0xFFFFFF);
-    
-    private ColorUIResource tickColor;
-    
-    private RangeModel primary;
-    private RangeModel secondary;
-    
-    private Insets boundInsets;
-    
-    private RangeModel internalSecondaryModel;
-    
-    private StatsModel primaryStats;
-    
-    private String primaryUnit;
-    private String secondaryUnit;
-
-        public void setPrimaryScaleUnit(String primaryUnit) {
-        this.primaryUnit = primaryUnit;
-    }
-    
-    public void setSecondayScaleUnit(String secondaryUnit) {
-        this.secondaryUnit = secondaryUnit;
-    }
-    
-    public StatsModel getStats() {
-        return primaryStats;
-    }
-    
-    public void setStats(StatsModel primaryStats) {
-        this.primaryStats = primaryStats;
-    }
-
-    public MemoryMeter() {
-        
-        secondaryUnit = "";
-        primaryUnit = "";
-        
-        boundInsets = new Insets(10, 10, 20, 20);
-        
-        tickColor = new ColorUIResource(0xdbdddb);
-        
-        primary = new RangeModel();
-        primary.setMinimum(0);
-        primary.setMaximum(100);
-        primary.setMinNormalized(0);
-        primary.setMaxNormalized(100);
-        
-        secondary = new RangeModel();
-        secondary.setMinimum(0);
-        secondary.setMaximum(100);
-        secondary.setMinNormalized(0);
-        secondary.setMaxNormalized(100);
-        
-        internalSecondaryModel = new RangeModel();
-    }
-    
-    public ColorUIResource getTickColor() {
-        return tickColor;
-    }
-    
-    public void setTickColor(ColorUIResource tickColor) {
-        this.tickColor = tickColor;
-    }
-    
-    public RangeModel getPrimaryModel() {
-        return primary;
-    }
-    
-    public RangeModel getSecondaryModel() {
-        return secondary;
-    }
-    
-    protected Rectangle getOuterBounds() {
-        return new Rectangle(0, 0, getWidth(), getHeight());
-    }
-    
-    protected Rectangle getBoundsWithInsets(Rectangle bounds) {
-        return new Rectangle(bounds.x + boundInsets.left,
-                             bounds.y + boundInsets.top,
-                             bounds.width  - boundInsets.right,
-                             bounds.height - boundInsets.bottom);
-    }
-        
-    /**
-     * paint the outher frame, including the light border sorrounding
-     */
-    protected void paintOuterFrame(Graphics2D graphics, Rectangle bounds) {
-
-        RoundRectangle2D frame = new RoundRectangle2D.Float(bounds.x, bounds.y, bounds.width, bounds.height, 6, 6);
-
-        Paint paint = new GradientPaint(0, 0, MAIN_GRADIENT_TOP, 0, getHeight(), getBackground());
-        graphics.setPaint(paint);
-        graphics.fill(frame);
-        
-        paint = new GradientPaint(0, 0, MAIN_BORDER_COLOR, 0, getHeight(), getBackground());
-        graphics.setPaint(paint);
-        frame = new RoundRectangle2D.Float(bounds.x, bounds.y, bounds.width -1, bounds.height, 6, 6);
-        graphics.draw(frame);
-    }
-    
-    /**
-     * paint the track sorrounding the main bar
-     */
-    protected void paintMainBarTrackFill(Graphics2D graphics, Rectangle bounds) {
-        
-        Paint paint = new GradientPaint(0, 0, MAIN_GRADIENT_TOP, 0, bounds.height, Color.WHITE);
-        graphics.setPaint(paint);
-        RoundRectangle2D frame = new RoundRectangle2D.Float(0, 0, bounds.width, bounds.height, 6, 6);
-        graphics.fill(frame);
-    }
-    
-    /**
-     */
-    protected void paintMainBarTrackBorder(Graphics2D graphics, Rectangle bounds) {
-        Paint paint = new GradientPaint(0, 0, MAIN_BORDER_COLOR, getWidth(), 0, getBackground());
-        graphics.setPaint(paint);
-        
-        RoundRectangle2D frame = new RoundRectangle2D.Float(0, 0, bounds.width - 1, bounds.height, 6, 6);
-        graphics.draw(frame);
-    }
-
-    
-    /**
-     * this is the main bar, will it up to what is defined by the model
-     */
-    protected void paintMainBarFill(Graphics2D graphics, Rectangle bounds) {
-        Paint paint = new GradientPaint(0, 0, MAIN_BAR_BASE_COLOR, getWidth() * 2, 0, getBackground());
-        graphics.setPaint(paint);
-        
-        RoundRectangle2D frame =
-                new RoundRectangle2D.Float(0, 0, getPrimaryModel().getValueNormalized(),
-                                           bounds.height, 6, 6);
-        graphics.fill(frame);
-        
-        String value = String.valueOf(getPrimaryModel().getValue()) + " " + primaryUnit;
-        Rectangle2D fontBounds = font.getStringBounds(value, graphics.getFontRenderContext());
-        int width = (int) (bounds.width/2 - fontBounds.getWidth()/2) - 1;
-        
-        if (width > getPrimaryModel().getValueNormalized()) {
-            graphics.setPaint(MAIN_BAR_BASE_COLOR);
-        } else {
-            graphics.setPaint(getBackground());
-        }
-
-        int height  = (int) (bounds.height / 2 + fontBounds.getHeight()/2);
-        SwingUtilities2.drawString(this, graphics, value, width, height);
-    }
-    
-    /**
-     */
-    private void paintMainBar(Graphics2D g, Rectangle bounds) {
-        
-        Graphics2D graphics = (Graphics2D) g.create();
-                
-        graphics.translate(bounds.x, bounds.y);
-        paintMainBarTrackFill(graphics, bounds);
-        
-        paintMainBarFill(graphics, bounds);
-        
-        paintMainBarTrackBorder(graphics, bounds);
-        graphics.dispose();
-    }
-    
-    /**
-     */
-    protected void drawBottomBar(Graphics2D g, Rectangle bounds) {
-
-        Graphics2D graphics = (Graphics2D) g.create();
-        graphics.translate(bounds.x, bounds.y + bounds.height);
-        
-        drawTickMark(graphics, bounds);
-        
-        paintSecondaryBarFill(graphics, bounds);
-        
-        graphics.dispose();
-    }
-    
-    /**
-     */
-    protected void drawTickMark(Graphics2D graphics, Rectangle bounds) {
-      
-        graphics.setPaint(MAIN_BORDER_COLOR);
-        
-        int smallTop = bounds.height - 5;
-        int smallBottom = bounds.height;
-
-        int mainTop = smallTop + 20;
-        int mainBottom = smallBottom - 15;
-      
-        // the first and last tick are always big, this is the first
-        graphics.drawLine(0, mainTop, 0, mainBottom);
-      
-        // the space between the vertical lines
-        double tickSpace = ((double) bounds.width) / TICK_NUM;
-      
-        internalSecondaryModel.setMaxNormalized(bounds.width);      
-        int numTicks = 0;
-
-        for (int x = 0; x < bounds.width; x += tickSpace + 0.5) {
-            if (numTicks % SMALL_TICK_NUM == 0) {
-              
-                graphics.drawLine(x, smallTop, x, smallBottom + 5);
-
-                internalSecondaryModel.setValue(x);
-            } else {
-                graphics.drawLine(x, smallTop, x, smallBottom);
-            }
-            numTicks++;
-        }
-        
-        // that's the last
-        graphics.drawLine(bounds.width, mainTop, bounds.width, mainBottom);
-        graphics.drawLine(0, smallTop, bounds.width, smallTop);
-        
-        drawStrings(graphics, mainBottom, mainTop, bounds.width);
-    }
-    
-    protected void drawStrings(Graphics2D graphics, int top, int bottom, int right) {
-      
-      // now draw the min/max values of both side of markers      
-      // top bar min value
-      FontMetrics fm = SwingUtilities2.getFontMetrics(this, font);
-      
-      String value = String.valueOf(getPrimaryModel().getMinimum()) + " " + primaryUnit;
-      int height = top + fm.getAscent()/2;
-      SwingUtilities2.drawString(this, graphics, value, 1, height);
-      
-      value = String.valueOf(getSecondaryModel().getMinimum()) + " " + secondaryUnit;
-      height = bottom;
-      SwingUtilities2.drawString(this, graphics, value, 1, height);
-      
-      value = String.valueOf(getPrimaryModel().getMaximum()) + " " + primaryUnit;
-      height = top + fm.getAscent()/2;
-
-      int width = (int) (right - font.getStringBounds(value, graphics.getFontRenderContext()).getWidth()) - 1;
-      SwingUtilities2.drawString(this, graphics, value, width, height);
-      
-      value = String.valueOf(getSecondaryModel().getMaximum()) + " " + secondaryUnit;
-      height = bottom;
-      width = (int) (right - font.getStringBounds(value, graphics.getFontRenderContext()).getWidth()) - 1;
-      SwingUtilities2.drawString(this, graphics, value, width, height);
-      
-      // now draw the actual value for the bottom bar, the top bar is drawn in
-      // its fill method
-      value = String.valueOf(getSecondaryModel().getValue()) + " " + secondaryUnit;
-      width = right/2;
-      Rectangle2D bounds = font.getStringBounds(value, graphics.getFontRenderContext());
-      width = (int) (width - bounds.getWidth()/2) - 1;
-      SwingUtilities2.drawString(this, graphics, value, width, height);
-      RoundRectangle2D frame = new RoundRectangle2D.Double(width - 2, height - bounds.getHeight(),
-                                                          bounds.getWidth() + 4, bounds.getHeight() + 4,
-                                                          4, 4);
-      graphics.draw(frame);
-    }
-    
-    protected void paintSecondaryBarFill(Graphics2D graphics, Rectangle bounds) {
-        
-        graphics.setPaint(MAIN_BAR_BASE_COLOR_TOP);
-        graphics.drawLine(1, bounds.height, getSecondaryModel().getValueNormalized() - 1, bounds.height);
-        
-        graphics.setPaint(MAIN_BAR_BASE_COLOR);
-        graphics.fillRect(1, bounds.height + 1, getSecondaryModel().getValueNormalized(), 2);
-    }
-    
-    protected void paintStats(Graphics2D graphics, Rectangle bounds) {
-        
-        int imageWidth = bounds.width - 2;
-        if (imageWidth < 0 || bounds.height < 0) {
-            return;
-        }
-        
-        StatsModel stats = getStats();
-        drawStats(graphics, stats, bounds.x, bounds.y, imageWidth, bounds.height);
-    }
-    
-    private void drawStats(Graphics2D graphics, StatsModel stats, int x, int y, int imageWidth, int height) {
-        if (stats != null) {
-            BufferedImage image = stats.getChart(imageWidth, height, STATS_BG,
-                                                 new ColorUIResource(getForeground()));
-       
-            paintStatsLabel(graphics, image, stats.getName());
-            graphics.drawImage(image, x, y, null);
-        }
-    }
-    
-    protected void paintStatsLabel(Graphics2D graphics, BufferedImage image, String label) {
-        int height = SwingUtilities2.getFontMetrics(this, font).getAscent() + 2;
-        if (height <= 0) {
-            return;
-        }
-        
-        Graphics2D imageGraphics = (Graphics2D) image.getGraphics();
-        imageGraphics.setColor(getForeground());
-        imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-        
-        SwingUtilities2.drawString(this, imageGraphics, label, 2, height);
-    }
-    
-    @Override
-    protected void paintComponent(Graphics g) {
-
-        Graphics2D graphics = (Graphics2D) g.create();
-        graphics.setFont(font);
-        
-        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-        graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
-        
-        Rectangle outerBounds = getOuterBounds();
-        Rectangle innerBounds = getBoundsWithInsets(outerBounds);
-        Rectangle statsBound =  getBoundsWithInsets(outerBounds);
-        
-        // move the bar close to the center
-        innerBounds.height = MAIN_BAR_HEIGHT;
-        innerBounds.y = outerBounds.height/2;
-        
-        // make the stats area cover the upper portion instead
-        statsBound.height = (outerBounds.height/2) - MAIN_BAR_HEIGHT;
-        
-        resetModels(0, innerBounds.width);
-
-        // some eye candy
-        paintOuterFrame(graphics, outerBounds);
-
-        // paint the usage stats
-        paintStats(graphics, statsBound);
-        
-        // main and bottom bars
-        paintMainBar(graphics, innerBounds);
-        drawBottomBar(graphics, innerBounds);
-        
-        graphics.dispose();
-    }
-    
-    private void resetModels(int min, int max) {
-        
-        getPrimaryModel().setMaxNormalized(max);
-        getPrimaryModel().setMinNormalized(min);
-        
-        RangeModel model = getSecondaryModel();
-        model.setMaxNormalized(max);
-        model.setMinNormalized(min);
-        
-        internalSecondaryModel.setMaximum(model.getMaximum());
-        internalSecondaryModel.setMinimum(model.getMinimum());
-        internalSecondaryModel.setValue(model.getValue());
-        
-        internalSecondaryModel.setMaxNormalized(max);
-        internalSecondaryModel.setMinNormalized(0);
-    }
-    
-    @Override
-    @Transient
-    public Dimension getPreferredSize() {
-        return new Dimension(850, 150);
-    }
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsController.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,228 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import com.redhat.thermostat.client.core.controllers.VmInformationServiceController;
-import com.redhat.thermostat.client.core.views.BasicView.Action;
-import com.redhat.thermostat.client.core.views.UIComponent;
-import com.redhat.thermostat.client.stats.memory.locale.LocaleResources;
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.NotImplementedException;
-import com.redhat.thermostat.common.Timer;
-import com.redhat.thermostat.common.Timer.SchedulingType;
-import com.redhat.thermostat.common.appctx.ApplicationContext;
-import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.locale.Translate;
-import com.redhat.thermostat.common.model.VmMemoryStat;
-import com.redhat.thermostat.common.model.VmMemoryStat.Generation;
-import com.redhat.thermostat.common.model.VmMemoryStat.Space;
-import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
-
-class MemoryStatsController implements VmInformationServiceController {
-
-    private final MemoryStatsView view;
-    private final VmMemoryStatDAO vmDao;
-   
-    private final VmRef ref;
-    private final Timer timer;
-    
-    private final Map<String, Payload> regions;
-    
-    private VMCollector collector;
-    
-    class VMCollector implements Runnable {
-
-        private long desiredUpdateTimeStamp = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1);
-
-        @Override
-        public void run() {
-            List<VmMemoryStat> vmInfo = vmDao.getLatestVmMemoryStats(ref, desiredUpdateTimeStamp);
-            for (VmMemoryStat memoryStats: vmInfo) {
-                List<Generation> generations = memoryStats.getGenerations();
-                
-                for (Generation generation : generations) {
-                    List<Space> spaces = generation.spaces;
-                    for (Space space: spaces) {
-                        Payload payload = regions.get(space.name);
-                        if (payload == null) {
-                            payload = new Payload();
-                            payload.setName(space.name);
-                        }
-
-                        Scale usedScale = normalizeScale(space.used, space.capacity);
-                        double used = Scale.convertTo(usedScale, space.used, 100);
-                        double maxUsed = Scale.convertTo(usedScale, space.capacity, 100);
-                        
-                        payload.setUsed(used);
-                        payload.setMaxUsed(maxUsed);
-                        payload.setUsedUnit(usedScale);
-                        
-                        Scale maxScale = normalizeScale(space.capacity, space.maxCapacity);
-                        double capacity = Scale.convertTo(maxScale, space.capacity, 100);
-                        double maxCapacity = Scale.convertTo(maxScale, space.maxCapacity, 100);
-                        
-                        payload.setCapacity(capacity);
-                        payload.setMaxCapacity(maxCapacity);
-                        payload.setCapacityUnit(maxScale);
-                        
-                        String tooltip = space.name + ": used: " + used + " " + usedScale +
-                                ", capacity: " + capacity + " " + maxScale +
-                                ", max capacity: " + maxCapacity + " " + maxScale;
-                        
-                        payload.setTooltip(tooltip);
-                        
-                        StatsModel model = payload.getModel();
-                        if (model == null) {
-                            model = new StatsModel();
-                            model.setName(space.name);
-                            model.setRange(3600);
-                        }
-                        
-                        // normalize this always in the same unit
-                        model.addData(memoryStats.getTimeStamp(),
-                                      Scale.convertTo(Scale.MiB, space.used, 100));
-                        
-                        payload.setModel(model);
-                        if (regions.containsKey(space.name)) {
-                            view.updateRegion(payload.clone());
-                        } else {
-                            view.addRegion(payload.clone());
-                            regions.put(space.name, payload);
-                        }
-                        
-                        view.requestRepaint();
-                        desiredUpdateTimeStamp = Math.max(desiredUpdateTimeStamp, memoryStats.getTimeStamp());
-                    }
-                }
-            }
-        }
-    }
-    
-    public MemoryStatsController(final VmMemoryStatDAO vmMemoryStatDao, final VmRef ref, MemoryStatsViewProvider viewProvider) {
-        
-        regions = new HashMap<>();
-        this.ref = ref;
-        vmDao = vmMemoryStatDao;
-        view = viewProvider.createView();
-        
-        timer = ApplicationContext.getInstance().getTimerFactory().createTimer();
-        
-        collector = new VMCollector();
-        timer.setAction(collector);
-        
-        timer.setInitialDelay(0);
-        timer.setDelay(1000);
-        timer.setTimeUnit(TimeUnit.MILLISECONDS);
-        timer.setSchedulingType(SchedulingType.FIXED_RATE);
-
-        view.addActionListener(new ActionListener<Action>() {
-            @Override
-            public void actionPerformed(ActionEvent<Action> actionEvent) {
-                switch(actionEvent.getActionId()) {
-                    case HIDDEN:
-                        stop();
-                        break;
-                        
-                    case VISIBLE:
-                        start();
-                        break;
-                        
-                    default:
-                        throw new NotImplementedException("unknown event: " + actionEvent.getActionId());
-                }
-            }
-        });
-    }
-    
-    // for testing
-    VMCollector getCollector() {
-        return collector;
-    };
-    
-    Map<String, Payload> getRegions() {
-        return regions;
-    }
-    
-    private Scale normalizeScale(long min, long max) {
-        // FIXME: this is very dumb and very inefficient
-        // needs cleanup
-        Scale minScale = Scale.getScale(min);
-        Scale maxScale = Scale.getScale(max);
-        
-        Scale[] scales = Scale.values();
-        int maxID = 0;
-        int minID = 0;
-        for (int i = 0; i < scales.length; i++) {
-            if (scales[i] == minScale) {
-                minID = i;
-            }
-            if (scales[i] == maxScale) {
-                maxID = i;
-            }
-        }
-        while (maxID - minID >= 2) {
-            minID++;
-        }
-        return scales[minID];
-    }
-    
-    private void start() {
-        timer.start();
-    }
-
-    private void stop() {
-        timer.stop();
-    }
-
-    @Override
-    public String getLocalizedName() {
-        Translate<LocaleResources> t = LocaleResources.createLocalizer();
-        return t.localize(LocaleResources.VM_INFO_TAB_MEMORY);
-    }
-
-    @Override
-    public UIComponent getView() {
-        return (UIComponent) view;
-    }
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsPanelActivator.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-import java.util.Map;
-
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-
-import com.redhat.thermostat.client.core.VmInformationService;
-import com.redhat.thermostat.client.osgi.service.ApplicationService;
-import com.redhat.thermostat.common.MultipleServiceTracker;
-import com.redhat.thermostat.common.MultipleServiceTracker.Action;
-import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
-
-public class MemoryStatsPanelActivator implements BundleActivator {
-
-    private MultipleServiceTracker tracker;
-    private ServiceRegistration memoryStatRegistration;
-
-    @Override
-    public void start(final BundleContext context) throws Exception {
-        MemoryStatsViewProvider provider = new SwingMemoryStatsViewProvider();
-        context.registerService(MemoryStatsViewProvider.class.getName(), provider, null);
-        
-        Class<?>[] deps = new Class<?>[] {
-            ApplicationService.class,
-            VmMemoryStatDAO.class,
-        };
-
-        tracker = new MultipleServiceTracker(context, deps, new Action() {
-            
-            @Override
-            public void dependenciesUnavailable() {
-                memoryStatRegistration.unregister();
-                memoryStatRegistration = null;
-            }
-
-            @Override
-            public void dependenciesAvailable(Map<String, Object> services) {
-                VmMemoryStatDAO memoryStatDao = (VmMemoryStatDAO) services.get(VmMemoryStatDAO.class.getName());
-                MemoryStatsService impl = new MemoryStatsService(memoryStatDao);
-                memoryStatRegistration = context.registerService(VmInformationService.class.getName(), impl , null);
-            }
-        });
-        tracker.open();
-
-    }
-
-    @Override
-    public void stop(BundleContext context) throws Exception {
-        tracker.close();
-    }
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsService.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-import com.redhat.thermostat.client.core.VmFilter;
-import com.redhat.thermostat.client.core.VmInformationService;
-import com.redhat.thermostat.client.core.controllers.VmInformationServiceController;
-import com.redhat.thermostat.client.osgi.service.AlwaysMatchFilter;
-import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.utils.OSGIUtils;
-
-class MemoryStatsService implements VmInformationService {
-    
-    private VmFilter filter = new AlwaysMatchFilter();
-
-    private VmMemoryStatDAO vmMemoryStatDao;
-
-    public MemoryStatsService(VmMemoryStatDAO vmMemoryStatDao) {
-        this.vmMemoryStatDao = vmMemoryStatDao;
-    }
-    
-    @Override
-    public VmInformationServiceController getInformationServiceController(VmRef ref) {
-        MemoryStatsViewProvider viewProvider = OSGIUtils.getInstance().getService(MemoryStatsViewProvider.class);
-        return new MemoryStatsController(vmMemoryStatDao, ref, viewProvider);
-    }
-
-    @Override
-    public VmFilter getFilter() {
-        return filter;
-    }
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsView.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.core.views.UIComponent;
-
-public abstract class MemoryStatsView extends BasicView implements UIComponent {
-    
-    public abstract void addRegion(Payload region);
-    public abstract void updateRegion(Payload region);
-    
-    public abstract void requestRepaint();
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsViewImpl.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,152 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-import java.awt.Component;
-import java.awt.Dimension;
-import java.beans.Transient;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.swing.Box;
-import javax.swing.BoxLayout;
-import javax.swing.JPanel;
-import javax.swing.SwingUtilities;
-
-import com.redhat.thermostat.client.core.views.BasicView;
-import com.redhat.thermostat.client.ui.ComponentVisibleListener;
-import com.redhat.thermostat.client.ui.SwingComponent;
-import com.redhat.thermostat.swing.HeaderPanel;
-
-public class MemoryStatsViewImpl extends MemoryStatsView implements SwingComponent {
-
-    private static final long REPAINT_DELAY = 500;
-    private long lastRepaint;
-    
-    private HeaderPanel visiblePanel;
-    private JPanel realPanel;
-    
-    private final Map<String, MemoryGraphPanel> regions;
-    
-    private Dimension preferredSize;
-    
-    public MemoryStatsViewImpl() {
-        super();
-        visiblePanel = new HeaderPanel();
-        regions = new HashMap<>();
- 
-        preferredSize = new Dimension(0, 0);
-        
-        visiblePanel.setHeader("Memory Regions");
-
-        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
-            @Override
-            public void componentShown(Component component) {
-                notifier.fireAction(Action.VISIBLE);
-            }
-
-            @Override
-            public void componentHidden(Component component) {
-                notifier.fireAction(Action.HIDDEN);
-            }
-        });
-
-        realPanel = new JPanel();
-        realPanel.setLayout(new BoxLayout(realPanel, BoxLayout.Y_AXIS));
-        visiblePanel.setContent(realPanel);
-    }
-    
-    @Transient
-    public Dimension getPreferredSize() {
-        return new Dimension(preferredSize);
-    }
-    
-    @Override
-    public void updateRegion(final Payload region) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                MemoryGraphPanel memoryGraphPanel = regions.get(region.getName());
-                memoryGraphPanel.setMemoryGraphProperties(region);
-            }
-        });
-    }
-    
-    @Override
-    public void addRegion(final Payload region) {
-
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                MemoryGraphPanel memoryGraphPanel = new MemoryGraphPanel();
-                
-                realPanel.add(memoryGraphPanel);
-                realPanel.add(Box.createRigidArea(new Dimension(5,5)));
-                regions.put(region.getName(), memoryGraphPanel);
-                
-                // components are stacked up vertically in this panel
-                Dimension memoryGraphPanelMinSize = memoryGraphPanel.getMinimumSize();
-                preferredSize.height += memoryGraphPanelMinSize.height + 5;
-                if (preferredSize.width < (memoryGraphPanelMinSize.width + 5)) {
-                    preferredSize.width = memoryGraphPanelMinSize.width + 5;
-                }
-
-                updateRegion(region);
-                realPanel.revalidate();
-            }
-        });
-    }
-
-    @Override
-    public Component getUiComponent() {
-        return visiblePanel;
-    }
-
-    @Override
-    public void requestRepaint() {
-        // really only repaint every REPAINT_DELAY milliseconds
-        long now = System.currentTimeMillis();
-        if (now - lastRepaint > REPAINT_DELAY) {
-            visiblePanel.repaint();
-            lastRepaint = System.currentTimeMillis();
-        }
-    }
-    
-    public BasicView getView() {
-        return this;
-    }
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/MemoryStatsViewProvider.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-import com.redhat.thermostat.client.core.views.ViewProvider;
-
-public interface MemoryStatsViewProvider extends ViewProvider {
-
-    @Override
-    public MemoryStatsView createView();
-    
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/Payload.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,145 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
-
-public class Payload implements Cloneable {
-
-    private String name;
-    private String tooltip;
-    
-    private double capacity;
-    private double maxCapacity;
-    private double maxUsed;
-    private double used;
-    
-    private Scale usedUnit;
-    private Scale capacityUnit;
-    
-    private StatsModel model;
-    
-    public void setModel(StatsModel model) {
-        this.model = model;
-    }
-    
-    public StatsModel getModel() {
-        return model;
-    }
-    
-    public void setCapacityUnit(Scale capacityUnit) {
-        this.capacityUnit = capacityUnit;
-    }
-    
-    public Scale getCapacityUnit() {
-        return capacityUnit;
-    }
-    
-    public void setUsedUnit(Scale usedUnit) {
-        this.usedUnit = usedUnit;
-    }
-    
-    public Scale getUsedUnit() {
-        return usedUnit;
-    }
-    
-    public double getMaxCapacity() {
-        return maxCapacity;
-    }
-    
-    public void setMaxCapacity(double maxCapacity) {
-        this.maxCapacity = maxCapacity;
-    }
-    
-    public double getUsed() {
-        return used;
-    }
-    
-    public void setUsed(double used) {
-        this.used = used;
-    }
-    
-    public double getMaxUsed() {
-        return maxUsed;
-    }
-    
-    public void setMaxUsed(double maxUsed) {
-        this.maxUsed = maxUsed;
-    }
-    
-    public double getCapacity() {
-        return capacity;
-    }
-    
-    public void setCapacity(double capacity) {
-        this.capacity = capacity;
-    }
-    
-    public String getName() {
-        return name;
-    }
-    
-    public void setName(String name) {
-        this.name = name;
-    }
-    
-    public String getTooltip() {
-        return tooltip;
-    }
-    
-    public void setTooltip(String tooltip) {
-        this.tooltip = tooltip;
-    }
-    
-    @Override
-    protected Payload clone() {
-        
-        Payload copy = new Payload();
-        
-        copy.used = used;
-        copy.capacity = capacity;
-        copy.capacityUnit = capacityUnit;
-        copy.maxCapacity = maxCapacity;
-        copy.maxUsed = maxUsed;
-        copy.model = model.clone();
-        copy.name = name;
-        copy.tooltip = tooltip;
-        copy.usedUnit = usedUnit;
-        
-        return copy;
-    }
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/RangeModel.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-public class RangeModel {
-
-    private int minNormalized;
-    private double min;
-    
-    private int maxNormalized;
-    private double max;
- 
-    private double value;
- 
-    public double getMinimum() {
-        return min;
-    }
-
-    public void setMinimum(double newMinimum) {
-        this.min = newMinimum;
-    }
-
-    public double getMaximum() {
-        return max;
-    }
-
-    public void setMaximum(double newMaximum) {
-        this.max = newMaximum;
-    }
-
-    public void setMaxNormalized(int maxNormalized) {
-        this.maxNormalized = maxNormalized;
-    }
-    
-    public void setMinNormalized(int minNormalized) {
-        this.minNormalized = minNormalized;
-    }
-    
-    public double getValue() {
-        return value;
-    }
-
-    public void setValue(double newValue) {
-        this.value = newValue;
-    }
-    
-    int getMaxNormalized() {
-        return maxNormalized;
-    }
-    
-    int getMinNormalized() {
-        return minNormalized;
-    }
-    
-    public int getValueNormalized() {
-        double normalized = ((value - min) * (maxNormalized - minNormalized)/(max - min)) + minNormalized;
-        return (int) Math.round(normalized);
-    }
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/StatsModel.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,181 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-import java.awt.Graphics2D;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
-import java.util.Date;
-
-import javax.swing.plaf.ColorUIResource;
-
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.axis.DateAxis;
-import org.jfree.chart.axis.NumberAxis;
-import org.jfree.chart.plot.XYPlot;
-import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
-import org.jfree.data.time.Millisecond;
-import org.jfree.data.time.TimeSeries;
-import org.jfree.data.time.TimeSeriesCollection;
-import org.jfree.data.xy.XYDataset;
-import org.jfree.ui.RectangleInsets;
-
-public class StatsModel implements Cloneable {
-
-    private static final String lock = new String("MemoryStatsModelLock");
-
-    private String name;
-    
-    private TimeSeries dataSet;
-    
-    public StatsModel() {
-        dataSet = new TimeSeries("");
-    }
-    
-    BufferedImage getChart(int width, int height, ColorUIResource bgColor, ColorUIResource fgColor) {
-        JFreeChart chart = createChart(bgColor, fgColor);
-        
-        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
-        chart.draw((Graphics2D) image.getGraphics(), new Rectangle2D.Double(0, 0, width, height), null);
-        
-        return image;
-    }
-    
-    public String getName() {
-        return name;
-    }
-    
-    public void setName(String name) {
-        dataSet.setDescription(name);
-        this.name = name;
-    }
-    
-    public void setRange(int seconds) {
-        dataSet.setMaximumItemCount(seconds);
-    }
-    
-    public void addData(long timestamp, double value) {
-        Millisecond millisecond = new Millisecond(new Date(timestamp));
-        synchronized (lock) {
-            if (dataSet.getValue(millisecond) == null) {
-                dataSet.add(millisecond, value);
-                dataSet.removeAgedItems(true);
-            }
-        }
-    }
-    
-    @Override
-    protected StatsModel clone() {
-        
-        StatsModel model = new StatsModel();
-        model.setName(name);
-        model.setRange(dataSet.getMaximumItemCount());
-        
-        try {
-            model.dataSet = dataSet.createCopy(0, dataSet.getItemCount() - 1);
-        } catch (CloneNotSupportedException e) {
-            // ah... it's supported here...
-            e.printStackTrace();
-        }
-        
-        return model;
-    }
-    
-    /**
-     * Creates a chart.
-     *
-     * @return a chart.
-     */
-    private JFreeChart createChart(ColorUIResource bgColor, ColorUIResource fgColor) {
-
-        XYDataset priceData = null;
-        synchronized (lock) {            
-            try {
-                priceData = new TimeSeriesCollection(dataSet.createCopy(0,
-                                                     dataSet.getItemCount() - 1));
-            } catch (CloneNotSupportedException e) {
-                e.printStackTrace();
-            }
-        }
-
-        XYPlot plot = new XYPlot();
-        
-        plot.setDomainGridlinesVisible(false);
-        plot.setDomainCrosshairVisible(false);
-        plot.setRangeGridlinesVisible(false);
-        plot.setRangeCrosshairVisible(false);
-                
-        DateAxis dateAxis = new DateAxis();
-        
-        dateAxis.setTickLabelsVisible(false);
-        dateAxis.setTickMarksVisible(false);
-        dateAxis.setAxisLineVisible(false);
-        dateAxis.setNegativeArrowVisible(false);
-        dateAxis.setPositiveArrowVisible(false);
-        dateAxis.setVisible(false);
-        
-        NumberAxis numberAxis = new NumberAxis();
-        numberAxis.setTickLabelsVisible(false);
-        numberAxis.setTickMarksVisible(false);
-        numberAxis.setAxisLineVisible(false);
-        numberAxis.setNegativeArrowVisible(false);
-        numberAxis.setPositiveArrowVisible(false);
-        numberAxis.setVisible(false);
-        numberAxis.setAutoRangeIncludesZero(false);
-        
-        plot.setDomainAxis(dateAxis);
-        plot.setRangeAxis(numberAxis);
-        plot.setDataset(priceData);
-        
-        plot.setInsets(new RectangleInsets(-1, -1, 0, 0));
-        
-        plot.setRenderer(new StandardXYItemRenderer(StandardXYItemRenderer.LINES));
-        plot.setBackgroundPaint(bgColor);
-        
-        JFreeChart chart = new JFreeChart(null, JFreeChart.DEFAULT_TITLE_FONT, plot, false);
-        
-        plot.getRenderer().setSeriesPaint(0, fgColor);
-        chart.setAntiAlias(true);
-        chart.setBorderVisible(false);
-        
-        return chart;
-    }
-    
-    TimeSeries getDataSet() {
-        return dataSet;
-    }
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/SwingMemoryStatsViewProvider.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-public class SwingMemoryStatsViewProvider implements MemoryStatsViewProvider {
-
-    @Override
-    public MemoryStatsView createView() {
-        return new MemoryStatsViewImpl();
-    }
-
-}
--- a/client/memory-stats-panel/src/main/java/com/redhat/thermostat/client/stats/memory/locale/LocaleResources.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory.locale;
-
-import com.redhat.thermostat.common.locale.Translate;
-
-public enum LocaleResources {
-
-    VM_INFO_TAB_MEMORY,
-    RESOURCE_MISSING;
-    
-    public static final String RESOURCE_BUNDLE =
-            "com.redhat.thermostat.client.stats.memory.locale.strings";
-    
-    public static Translate<LocaleResources> createLocalizer() {
-        return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class);
-    }
-}
--- a/client/memory-stats-panel/src/main/resources/com/redhat/thermostat/client/stats/memory/locale/strings.properties	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-RESOURCE_MISSING = Missing translation!
-VM_INFO_TAB_MEMORY = Memory
\ No newline at end of file
--- a/client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/MemoryStatsControllerTest.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,269 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.Timer;
-import com.redhat.thermostat.common.Timer.SchedulingType;
-import com.redhat.thermostat.common.TimerFactory;
-import com.redhat.thermostat.common.appctx.ApplicationContext;
-import com.redhat.thermostat.common.appctx.ApplicationContextUtil;
-import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
-import com.redhat.thermostat.common.dao.VmRef;
-import com.redhat.thermostat.common.model.VmMemoryStat;
-import com.redhat.thermostat.common.model.VmMemoryStat.Generation;
-import com.redhat.thermostat.common.model.VmMemoryStat.Space;
-
-public class MemoryStatsControllerTest {
-
-    private List<Generation> generations = new ArrayList<>();
-    
-    private VmMemoryStatDAO memoryStatDao;
-    private MemoryStatsView view;
-    private Timer timer;
-    
-    private ActionListener<MemoryStatsView.Action> viewListener;
-    
-    private MemoryStatsController controller;
-    
-    private Space canary;
-
-    
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Before
-    public void setUp() {
-        timer = mock(Timer.class);
-        ArgumentCaptor<Runnable> actionCaptor = ArgumentCaptor.forClass(Runnable.class);
-        doNothing().when(timer).setAction(actionCaptor.capture());
-        
-        TimerFactory timerFactory = mock(TimerFactory.class);
-        when(timerFactory.createTimer()).thenReturn(timer);
-        ApplicationContext.getInstance().setTimerFactory(timerFactory);
-        
-        List<VmMemoryStat> vmInfo = new ArrayList<>();
-        
-        for (int i = 0; i < 2; i++) {
-            Generation generation = new Generation();
-            generation.name = "fluff" + i;
-            generation.spaces = new ArrayList<>();
-            for (int j = 0; j < 2; j++) {
-                Space space = new Space();
-                space.name = "fluffer" + i + j;
-                space.used = 100;
-                space.capacity = 1000;
-                space.maxCapacity = 10000;
-                
-                generation.spaces.add(space);
-            }
-            generations.add(generation);
-        }
-        
-        // special payload because the others have all the same values
-        canary = new Space();
-        canary.name = "canary";
-        canary.used = 1;
-        canary.capacity = 2;
-        canary.maxCapacity = 3;
-        
-        long timestamp = 1;
-        int vmID = 1;
-        for (int i = 0; i < 5; i++) {
-            VmMemoryStat vmMemory = new VmMemoryStat(timestamp++, vmID, generations);
-            vmInfo.add(vmMemory);
-        }
-        
-        generations.get(0).spaces.add(canary);
-        
-        memoryStatDao = mock(VmMemoryStatDAO.class);
-        when(memoryStatDao.getLatestVmMemoryStats(any(VmRef.class), anyLong())).thenReturn(vmInfo);
-        
-        view = mock(MemoryStatsView.class);
-        MemoryStatsViewProvider viewProvider = mock(MemoryStatsViewProvider.class);
-        when(viewProvider.createView()).thenReturn(view);
-        
-        ArgumentCaptor<ActionListener> viewArgumentCaptor =
-                ArgumentCaptor.forClass(ActionListener.class);
-        doNothing().when(view).addActionListener(viewArgumentCaptor.capture());
-
-        VmRef ref = mock(VmRef.class);
-        
-        controller = new MemoryStatsController(memoryStatDao, ref, viewProvider);
-        
-        viewListener = viewArgumentCaptor.getValue();
-    }
-    
-    @Test
-    public void testStartStopTimer() {
-        viewListener.actionPerformed(new ActionEvent<>(view, MemoryStatsView.Action.VISIBLE));
-
-        verify(timer).start();
-        verify(timer).setSchedulingType(SchedulingType.FIXED_RATE);
-
-        viewListener.actionPerformed(new ActionEvent<>(view, MemoryStatsView.Action.HIDDEN));
-
-        verify(timer).stop();
-    }
-
-    @Test
-    public void testPayloadContainSpaces() {
-        MemoryStatsController.VMCollector collettor = controller.getCollector();
-        collettor.run();
-        
-        Map<String, Payload> regions = controller.getRegions();
-        assertEquals(5, regions.size());
-        
-        assertTrue(regions.containsKey("fluffer00"));
-        assertTrue(regions.containsKey("fluffer01"));
-        assertTrue(regions.containsKey("fluffer10"));
-        assertTrue(regions.containsKey("fluffer11"));
-        
-        assertTrue(regions.containsKey("canary"));
-    }
-    
-    @Test
-    public void testValues() {
-        MemoryStatsController.VMCollector collettor = controller.getCollector();
-        collettor.run();
-        
-        Map<String, Payload> regions = controller.getRegions();
-
-        Payload payload = regions.get("fluffer00");
-        assertEquals("fluffer00", payload.getName());
-        assertEquals(10000, payload.getMaxCapacity(), 0);
-        assertEquals(1000, payload.getCapacity(), 0);
-        assertEquals(100, payload.getUsed(), 0);
-        
-        payload = regions.get("canary");
-        assertEquals("canary", payload.getName());
-        assertEquals(3, payload.getMaxCapacity(), 0);
-        assertEquals(2, payload.getCapacity(), 0);
-        assertEquals(1, payload.getUsed(), 0);
-        
-        // the value above all ensure the same scale is used
-        String tooltip = payload.getName() + ": used: " + payload.getUsed() + " " +
-                         payload.getUsedUnit() + ", capacity: " +
-                         payload.getCapacity() + " " + payload.getUsedUnit() +
-                         ", max capacity: " + payload.getMaxCapacity() + " " +
-                         payload.getUsedUnit();
-        
-        assertEquals(tooltip, payload.getTooltip());
-    }
-    
-
-    @Test
-    public void testTimerFetchesMemoryDataDeltaOnly() {
-        ArgumentCaptor<Long> timeStampCaptor = ArgumentCaptor.forClass(Long.class);
-
-        final long DATA_TIMESTAMP = System.currentTimeMillis() + 1000000000;
-        Space space = new Space();
-        space.capacity = 10;
-        space.maxCapacity = 20;
-        space.used = 5;
-        Generation gen = new Generation();
-        gen.name = "foobar";
-        gen.spaces = Arrays.asList(space);
-        VmMemoryStat stat = new VmMemoryStat();
-        stat.setTimeStamp(DATA_TIMESTAMP);
-        stat.setGenerations(Arrays.asList(gen));
-
-        when(memoryStatDao.getLatestVmMemoryStats(isA(VmRef.class), anyLong())).thenReturn(Arrays.asList(stat));
-
-        Runnable timerAction = controller.getCollector();
-
-        timerAction.run();
-        timerAction.run();
-
-        verify(memoryStatDao, times(2)).getLatestVmMemoryStats(isA(VmRef.class), timeStampCaptor.capture());
-
-        long timeStamp1 = timeStampCaptor.getAllValues().get(0);
-        assertTimeStampIsAround(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1), timeStamp1);
-
-        long timeStamp2 = timeStampCaptor.getAllValues().get(1);
-        assertTimeStampIsAround(DATA_TIMESTAMP, timeStamp2);
-    }
-
-    @Test
-    public void testTimerFetchesMemoryDataDeltaOnlyEvenWithNoData() {
-        ArgumentCaptor<Long> timeStampCaptor = ArgumentCaptor.forClass(Long.class);
-
-        Runnable timerAction = controller.getCollector();
-
-        timerAction.run();
-        timerAction.run();
-
-        verify(memoryStatDao, times(2)).getLatestVmMemoryStats(isA(VmRef.class), timeStampCaptor.capture());
-
-        long timeStamp1 = timeStampCaptor.getAllValues().get(0);
-        assertTimeStampIsAround(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1), timeStamp1);
-
-        long timeStamp2 = timeStampCaptor.getAllValues().get(1);
-        assertTimeStampIsAround(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1), timeStamp2);
-    }
-
-    private void assertTimeStampIsAround(long expected, long actual) {
-        assertTrue(actual <= expected + 1000);
-        assertTrue(actual >= expected - 1000);
-    }
-
-    @After
-    public void tearDown() {
-        ApplicationContextUtil.resetApplicationContext();
-    }
-}
--- a/client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/MemoryStatsPanelActivatorTest.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.test.StubBundleContext;
-
-public class MemoryStatsPanelActivatorTest {
-
-    @Test
-    public void verifyStartRegistersViewProvider() throws Exception {
-        StubBundleContext ctx = new StubBundleContext();
-        MemoryStatsPanelActivator activator = new MemoryStatsPanelActivator();
-        activator.start(ctx);
-        assertTrue(ctx.isServiceRegistered(MemoryStatsViewProvider.class.getName(), SwingMemoryStatsViewProvider.class));
-        assertEquals(1, ctx.getAllServices().size());
-    }
-}
--- a/client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/PayloadTest.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-import static org.junit.Assert.*;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.common.utils.DisplayableValues.Scale;
-
-public class PayloadTest {
-
-    @Test
-    public void testClone() {
-        
-        StatsModel model = new StatsModel();
-        model.setName("fluffModel");
-        model.setRange(100);
-        model.addData(500, 2.0);
-        model.addData(501, 2.1);
-        
-        Payload source = new Payload();
-        source.setCapacity(10.0);
-        source.setName("fluff");
-        source.setCapacityUnit(Scale.GiB);
-        source.setMaxCapacity(100.0);
-        source.setMaxUsed(5.0);
-        source.setUsed(3.0);
-        source.setUsedUnit(Scale.MiB);
-        source.setModel(model);
-        source.setTooltip("fluffTooltip");
-        
-        Payload cloned = source.clone();
-        assertNotSame(cloned, source);
-        
-        assertEquals(source.getName(), cloned.getName());
-        assertEquals(source.getCapacity(), cloned.getCapacity(), 0);
-        assertEquals(source.getCapacityUnit(), cloned.getCapacityUnit());
-        assertEquals(source.getMaxCapacity(), cloned.getMaxCapacity(), 0);
-        assertEquals(source.getMaxUsed(), cloned.getMaxUsed(), 0);
-        assertEquals(source.getTooltip(), cloned.getTooltip());
-        assertEquals(source.getUsed(), cloned.getUsed(), 0);
-        assertEquals(source.getUsedUnit(), cloned.getUsedUnit());
-        assertNotSame(source.getModel(), cloned.getModel());
-
-        assertEquals(source.getModel().getName(), cloned.getModel().getName());
-    }
-}
--- a/client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/RangeModelTest.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-import static org.junit.Assert.*;
-import junit.framework.Assert;
-
-import org.junit.Test;
-
-public class RangeModelTest {
-
-    @Test
-    public void testSameRange() {
-        RangeModel model = new RangeModel();
-        
-        model.setMaximum(10);
-        model.setMinimum(0);
-        model.setValue(5);
-        
-        model.setMaxNormalized(10);
-        model.setMinNormalized(0);
-        
-        
-        Assert.assertEquals((int) model.getValue(), model.getValueNormalized());
-    }
-
-    @Test
-    public void testDoubleRange() {
-        RangeModel model = new RangeModel();
-        
-        model.setMaximum(10);
-        model.setMinimum(0);
-        model.setValue(5);
-        
-        model.setMaxNormalized(20);
-        model.setMinNormalized(0);
-        
-        
-        Assert.assertEquals(10, model.getValueNormalized());
-    }
-    
-    @Test
-    public void testRanges() {
-        RangeModel model = new RangeModel();
-        
-        model.setMaximum(10);
-        model.setMinimum(0);
-        model.setValue(5);
-        
-        model.setMaxNormalized(40);
-        model.setMinNormalized(0);
-                
-        Assert.assertEquals(20, model.getValueNormalized());
-        
-        model.setMaxNormalized(60);
-        model.setMinNormalized(0);
-                
-        Assert.assertEquals(30, model.getValueNormalized());
-                
-        model.setMaxNormalized(200);
-        model.setMinNormalized(100);
-                
-        Assert.assertEquals(150, model.getValueNormalized());
-        
-        model.setMaximum(100);
-        model.setMinimum(0);
-        model.setValue(50);
-        
-        model.setMaxNormalized(1);
-        model.setMinNormalized(0);
-                
-        Assert.assertEquals(1, model.getValueNormalized());
-        
-        model.setValue(49);
-        Assert.assertEquals(0, model.getValueNormalized());
-        
-        model.setMaximum(1.0);
-        model.setMinimum(0.0);
-        model.setValue(0.5);
-        
-        model.setMaxNormalized(100);
-        model.setMinNormalized(0);
-        
-        Assert.assertEquals(50, model.getValueNormalized());
-        
-        model.setValue(0.72);
-        Assert.assertEquals(72, model.getValueNormalized());
-    }
-}
--- a/client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/StatsModelTest.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory;
-
-import static org.junit.Assert.*;
-
-import org.jfree.data.time.TimeSeries;
-import org.junit.Test;
-
-public class StatsModelTest {
-
-    @Test
-    public void testClone() {
-        
-        StatsModel source = new StatsModel();
-        source.setName("fluffModel");
-        source.setRange(100);
-        source.addData(500, 2.0);
-        source.addData(501, 2.1);
-        
-        StatsModel cloned = source.clone();
-        
-        assertNotSame(cloned, source);
-        
-        assertEquals(source.getName(), cloned.getName());
-     
-        assertNotSame(cloned.getDataSet(), source.getDataSet());
-        
-        for (Object series : cloned.getDataSet().getItems()) {
-            assertTrue(source.getDataSet().getItems().contains(series));
-        }
-        
-        assertEquals(cloned.getDataSet().getItemCount(),
-                     source.getDataSet().getItemCount());
-    }
-
-}
--- a/client/memory-stats-panel/src/test/java/com/redhat/thermostat/client/stats/memory/locale/TranslateTest.java	Tue Oct 23 11:21:50 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client.stats.memory.locale;
-
-import java.io.IOException;
-import java.util.Locale;
-import java.util.Properties;
-
-import junit.framework.Assert;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.common.locale.Translate;
-
-public class TranslateTest {
-
-    private Locale lang;
-
-    @Before
-    public void setUp() {
-        this.lang = Locale.getDefault();
-        Locale.setDefault(Locale.US);
-    }
-
-    @After
-    public void tearDown() {
-        Locale.setDefault(lang);
-    }
-
-    @Test
-    public void verifyTranslationsAreThere() throws IOException {
-
-        String stringsResource = "/" + LocaleResources.RESOURCE_BUNDLE.replace(".", "/") + ".properties";
-
-        Properties props = new Properties();
-        props.load(getClass().getResourceAsStream(stringsResource));
-
-        Assert.assertEquals(LocaleResources.values().length, props.values().size());
-        Translate<LocaleResources> t = LocaleResources.createLocalizer();
-        Assert.assertEquals("Missing translation!", t.localize(LocaleResources.RESOURCE_MISSING));
-        Assert.assertEquals("Memory", t.localize(LocaleResources.VM_INFO_TAB_MEMORY));
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/swing/pom.xml	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>thermostat-osgi-memory-stats-panel</artifactId>
+    <groupId>com.redhat.thermostat</groupId>
+    <version>0.5.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>thermostat-osgi-memory-stats-panel-swing</artifactId>
+  <packaging>bundle</packaging>
+  <name>Thermostat Client VM Memory Monitor Swing plugin</name>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Private-Package>
+                com.redhat.thermostat.client.stats.memory.swing
+            </Private-Package>
+            <Bundle-Activator>com.redhat.thermostat.client.stats.memory.swing.MemoryStatsPanelActivator</Bundle-Activator>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-SymbolicName>com.redhat.thermostat.client.stats.memory.swing</Bundle-SymbolicName>
+            <!-- Do not autogenerate uses clauses in Manifests -->
+            <_nouses>true</_nouses>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.easytesting</groupId>
+      <artifactId>fest-swing</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>net.java.openjdk.cacio</groupId>
+      <artifactId>cacio-tta</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jfree</groupId>
+      <artifactId>jfreechart</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-common-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-osgi-memory-stats-panel-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-client-swing</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/swing/src/main/java/com/redhat/thermostat/client/stats/memory/swing/MemoryGraphPanel.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.swing;
+
+import java.awt.Dimension;
+import java.beans.Transient;
+
+import javax.swing.BoxLayout;
+import javax.swing.JPanel;
+
+import com.redhat.thermostat.client.stats.memory.core.MemoryMeter;
+import com.redhat.thermostat.client.stats.memory.core.Payload;
+
+@SuppressWarnings("serial")
+class MemoryGraphPanel extends JPanel {
+
+    private MemoryMeter meter;
+    
+    /**
+     * Create the panel.
+     */
+    public MemoryGraphPanel() {
+        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
+        meter = new MemoryMeter();
+        add(meter);
+    }
+    
+    public void setMemoryGraphProperties(Payload region) {
+
+        meter.getPrimaryModel().setMinimum(0);
+        meter.getPrimaryModel().setMaximum(region.getMaxUsed());
+        meter.getPrimaryModel().setValue(region.getUsed());
+        
+        meter.getSecondaryModel().setMinimum(0);
+        meter.getSecondaryModel().setMaximum(region.getMaxCapacity());
+        meter.getSecondaryModel().setValue(region.getCapacity());
+        
+        meter.setToolTipText(region.getTooltip());
+        
+        meter.setPrimaryScaleUnit(region.getUsedUnit().toString());
+        meter.setSecondayScaleUnit(region.getCapacityUnit().toString());
+        
+        meter.setStats(region.getModel());
+    }
+    
+    @Override
+    @Transient
+    public Dimension getPreferredSize() {
+        return meter.getPreferredSize();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/swing/src/main/java/com/redhat/thermostat/client/stats/memory/swing/MemoryStatsPanelActivator.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.swing;
+
+import java.util.Map;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+import com.redhat.thermostat.client.core.VmInformationService;
+import com.redhat.thermostat.client.osgi.service.ApplicationService;
+import com.redhat.thermostat.client.stats.memory.core.MemoryStatsService;
+import com.redhat.thermostat.client.stats.memory.core.MemoryStatsViewProvider;
+import com.redhat.thermostat.common.MultipleServiceTracker;
+import com.redhat.thermostat.common.MultipleServiceTracker.Action;
+import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
+
+public class MemoryStatsPanelActivator implements BundleActivator {
+
+    private MultipleServiceTracker tracker;
+    private ServiceRegistration memoryStatRegistration;
+
+    @Override
+    public void start(final BundleContext context) throws Exception {
+        MemoryStatsViewProvider provider = new SwingMemoryStatsViewProvider();
+        context.registerService(MemoryStatsViewProvider.class.getName(), provider, null);
+        
+        Class<?>[] deps = new Class<?>[] {
+            ApplicationService.class,
+            VmMemoryStatDAO.class,
+        };
+
+        tracker = new MultipleServiceTracker(context, deps, new Action() {
+            
+            @Override
+            public void dependenciesUnavailable() {
+                memoryStatRegistration.unregister();
+                memoryStatRegistration = null;
+            }
+
+            @Override
+            public void dependenciesAvailable(Map<String, Object> services) {
+                VmMemoryStatDAO memoryStatDao = (VmMemoryStatDAO) services.get(VmMemoryStatDAO.class.getName());
+                MemoryStatsService impl = new MemoryStatsService(memoryStatDao);
+                memoryStatRegistration = context.registerService(VmInformationService.class.getName(), impl , null);
+            }
+        });
+        tracker.open();
+
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        tracker.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/swing/src/main/java/com/redhat/thermostat/client/stats/memory/swing/MemoryStatsViewImpl.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.swing;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.beans.Transient;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+
+import com.redhat.thermostat.client.core.views.BasicView;
+import com.redhat.thermostat.client.stats.memory.core.MemoryStatsView;
+import com.redhat.thermostat.client.stats.memory.core.Payload;
+import com.redhat.thermostat.client.swing.SwingComponent;
+import com.redhat.thermostat.client.swing.components.HeaderPanel;
+import com.redhat.thermostat.client.ui.ComponentVisibleListener;
+
+public class MemoryStatsViewImpl extends MemoryStatsView implements SwingComponent {
+
+    private static final long REPAINT_DELAY = 500;
+    private long lastRepaint;
+    
+    private HeaderPanel visiblePanel;
+    private JPanel realPanel;
+    
+    private final Map<String, MemoryGraphPanel> regions;
+    
+    private Dimension preferredSize;
+    
+    public MemoryStatsViewImpl() {
+        super();
+        visiblePanel = new HeaderPanel();
+        regions = new HashMap<>();
+ 
+        preferredSize = new Dimension(0, 0);
+        
+        visiblePanel.setHeader("Memory Regions");
+
+        visiblePanel.addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component component) {
+                notifier.fireAction(Action.VISIBLE);
+            }
+
+            @Override
+            public void componentHidden(Component component) {
+                notifier.fireAction(Action.HIDDEN);
+            }
+        });
+
+        realPanel = new JPanel();
+        realPanel.setLayout(new BoxLayout(realPanel, BoxLayout.Y_AXIS));
+        visiblePanel.setContent(realPanel);
+    }
+    
+    @Transient
+    public Dimension getPreferredSize() {
+        return new Dimension(preferredSize);
+    }
+    
+    @Override
+    public void updateRegion(final Payload region) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                MemoryGraphPanel memoryGraphPanel = regions.get(region.getName());
+                memoryGraphPanel.setMemoryGraphProperties(region);
+            }
+        });
+    }
+    
+    @Override
+    public void addRegion(final Payload region) {
+
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                MemoryGraphPanel memoryGraphPanel = new MemoryGraphPanel();
+                
+                realPanel.add(memoryGraphPanel);
+                realPanel.add(Box.createRigidArea(new Dimension(5,5)));
+                regions.put(region.getName(), memoryGraphPanel);
+                
+                // components are stacked up vertically in this panel
+                Dimension memoryGraphPanelMinSize = memoryGraphPanel.getMinimumSize();
+                preferredSize.height += memoryGraphPanelMinSize.height + 5;
+                if (preferredSize.width < (memoryGraphPanelMinSize.width + 5)) {
+                    preferredSize.width = memoryGraphPanelMinSize.width + 5;
+                }
+
+                updateRegion(region);
+                realPanel.revalidate();
+            }
+        });
+    }
+
+    @Override
+    public Component getUiComponent() {
+        return visiblePanel;
+    }
+
+    @Override
+    public void requestRepaint() {
+        // really only repaint every REPAINT_DELAY milliseconds
+        long now = System.currentTimeMillis();
+        if (now - lastRepaint > REPAINT_DELAY) {
+            visiblePanel.repaint();
+            lastRepaint = System.currentTimeMillis();
+        }
+    }
+    
+    public BasicView getView() {
+        return this;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/swing/src/main/java/com/redhat/thermostat/client/stats/memory/swing/SwingMemoryStatsViewProvider.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.swing;
+
+import com.redhat.thermostat.client.stats.memory.core.MemoryStatsView;
+import com.redhat.thermostat.client.stats.memory.core.MemoryStatsViewProvider;
+
+public class SwingMemoryStatsViewProvider implements MemoryStatsViewProvider {
+
+    @Override
+    public MemoryStatsView createView() {
+        return new MemoryStatsViewImpl();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/swing/src/main/resources/com/redhat/thermostat/client/stats/memory/locale/strings.properties	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,2 @@
+RESOURCE_MISSING = Missing translation!
+VM_INFO_TAB_MEMORY = Memory
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/memory-stats-panel/swing/src/test/java/com/redhat/thermostat/client/stats/memory/swing/MemoryStatsPanelActivatorTest.java	Tue Oct 23 11:22:31 2012 -0400
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.stats.memory.swing;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import com.redhat.thermostat.client.stats.memory.core.MemoryStatsViewProvider;
+import com.redhat.thermostat.test.StubBundleContext;
+
+public class MemoryStatsPanelActivatorTest {
+
+    @Test
+    public void verifyStartRegistersViewProvider() throws Exception {
+        StubBundleContext ctx = new StubBundleContext();
+        MemoryStatsPanelActivator activator = new MemoryStatsPanelActivator();
+        activator.start(ctx);
+        assertTrue(ctx.isServiceRegistered(MemoryStatsViewProvider.class.getName(), SwingMemoryStatsViewProvider.class));
+        assertEquals(1, ctx.getAllServices().size());
+    }
+}