changeset 60:a55a4ed7e6b6

Update the text in the UI asynchronously
author Omair Majid <omajid@redhat.com>
date Mon, 30 Jan 2012 13:42:10 -0500
parents beab47f74ee6
children a4ac69374d2f
files src/com/redhat/thermostat/client/AsyncUiFacade.java src/com/redhat/thermostat/client/ChangeableText.java src/com/redhat/thermostat/client/DummyFacade.java src/com/redhat/thermostat/client/DummyUiFacadeFactory.java src/com/redhat/thermostat/client/HostPanelFacade.java src/com/redhat/thermostat/client/HostPanelFacadeImpl.java src/com/redhat/thermostat/client/Main.java src/com/redhat/thermostat/client/MainWindowFacade.java src/com/redhat/thermostat/client/MainWindowFacadeImpl.java src/com/redhat/thermostat/client/SummaryPanelFacade.java src/com/redhat/thermostat/client/SummaryPanelFacadeImpl.java src/com/redhat/thermostat/client/VmPanelFacade.java src/com/redhat/thermostat/client/VmPanelFacadeImpl.java src/com/redhat/thermostat/client/ui/AsyncFacadeManager.java src/com/redhat/thermostat/client/ui/ComponentVisibleListener.java src/com/redhat/thermostat/client/ui/HostPanel.java src/com/redhat/thermostat/client/ui/SimpleTable.java src/com/redhat/thermostat/client/ui/SummaryPanel.java src/com/redhat/thermostat/client/ui/VmPanel.java
diffstat 19 files changed, 683 insertions(+), 560 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/redhat/thermostat/client/AsyncUiFacade.java	Mon Jan 30 13:42:10 2012 -0500
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client;
+
+public interface AsyncUiFacade {
+
+    public void start();
+
+    public void stop();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/redhat/thermostat/client/ChangeableText.java	Mon Jan 30 13:42:10 2012 -0500
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class ChangeableText {
+
+    private final Set<TextListener> listeners = new HashSet<TextListener>();
+    private String text;
+
+    public static interface TextListener {
+        public void textChanged(ChangeableText text);
+    }
+
+    public ChangeableText(String text) {
+        this.text = text;
+    }
+
+    public synchronized void setText(String text) {
+        if (this.text.equals(text)) {
+            return;
+        }
+        this.text = text;
+        fireChanged();
+    }
+
+    public synchronized String getText() {
+        return text;
+    }
+
+    public synchronized void addListener(TextListener listener) {
+        this.listeners.add(listener);
+    }
+
+    public synchronized void removeListener(TextListener listener) {
+        this.listeners.remove(listener);
+    }
+
+    private void fireChanged() {
+        for (TextListener listener: listeners) {
+            listener.textChanged(this);
+        }
+    }
+
+}
--- a/src/com/redhat/thermostat/client/DummyFacade.java	Fri Jan 27 11:46:45 2012 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,321 +0,0 @@
-/*
- * Copyright 2012 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.client;
-
-import static com.redhat.thermostat.client.Translate._;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-
-import javax.swing.tree.DefaultMutableTreeNode;
-import javax.swing.tree.DefaultTreeModel;
-import javax.swing.tree.TreeModel;
-
-import com.redhat.thermostat.common.HostInfo;
-import com.redhat.thermostat.common.NetworkInfo;
-import com.redhat.thermostat.common.NetworkInterfaceInfo;
-import com.redhat.thermostat.common.VmInfo;
-import com.redhat.thermostat.common.VmMemoryStat;
-import com.redhat.thermostat.common.VmMemoryStat.Generation;
-import com.redhat.thermostat.common.VmMemoryStat.Space;
-
-public class DummyFacade implements SummaryPanelFacade, HostPanelFacade, VmPanelFacade, MainWindowFacade {
-
-    private final Random r = new Random();
-    private List<MemoryType> toDisplay = new ArrayList<MemoryType>();
-
-    private HostRef onlyAgent = new HostRef("a-random-string-of-letters-and-numbers", "agent on localhost");
-    private VmRef onlyVm = new VmRef(onlyAgent, "a-random-string-of-letters-and-numbers-or-perhaps-a-process-id", "super crazy awesome java app");
-    private String filter;
-
-    public DummyFacade() {
-        toDisplay.addAll(Arrays.asList(MemoryType.values()));
-    }
-
-    @Override
-    public long getTotalConnectedVms() {
-        return new VmRef[] { onlyVm }.length;
-    }
-
-    @Override
-    public long getTotalConnectedAgents() {
-        return 1;
-    }
-
-    @Override
-    public HostRef[] getHosts() {
-        return new HostRef[] { onlyAgent };
-    }
-
-    @Override
-    public VmRef[] getVms(HostRef ref) {
-        return new VmRef[] { onlyVm };
-    }
-
-    @Override
-    public TreeModel getHostVmTree() {
-        return new DefaultTreeModel(new DefaultMutableTreeNode());
-    }
-
-    @Override
-    public void setHostVmTreeFilter(String filter) {
-        this.filter = filter;
-    }
-
-    @Override
-    public List<String> getIssues() {
-        return new ArrayList<String>();
-    }
-
-    @Override
-    public HostInfo getHostInfo() {
-        String hostname = "host.example.com";
-        String osName = "Fedora 99";
-        String osKernel = "Linux 9.9.9.9";
-        String cpuModel = "Some CPU @ some speed GHz";
-        int cpuCount = 99;
-        long totalMemory = 1;
-        return new HostInfo(hostname, osName, osKernel, cpuModel, cpuCount, totalMemory);
-    }
-
-    @Override
-    public NetworkInfo getNetworkInfo() {
-        NetworkInfo info = new NetworkInfo();
-
-        NetworkInterfaceInfo eth0 = new NetworkInterfaceInfo("eth0");
-        eth0.setIp4Addr("1.1.1.1");
-        eth0.setIp6Addr("1:::::::::1");
-        info.addNetworkInterfaceInfo(eth0);
-
-        NetworkInterfaceInfo em0 = new NetworkInterfaceInfo("em0");
-        em0.setIp4Addr("256.256.256.256");
-        info.addNetworkInterfaceInfo(em0);
-
-        return info;
-    }
-
-    @Override
-    public VmInfo getVmInfo() {
-
-        // TODO hook into storage and return the actual VmInfo object
-        int vmPid = 0;
-        long startTime = System.currentTimeMillis() - 10000;
-        long stopTime = Integer.MIN_VALUE;
-        String javaVersion = "2.9.9";
-        String javaHome = "/usr/lib/jvm/java/jre/";
-        String mainClass = "com.foo.bar";
-        String commandLine = "some java program";
-        String vmName = "hotspot usb compiler";
-        String vmInfo = "future predictive mode";
-        String vmVersion = "99b99";
-        String vmArguments = "-XX:+EvenFasterPlease --X:+UNROLL_ALL_THE_LOOPS!";
-        Map<String, String> properties = new HashMap<String, String>();
-        Map<String, String> environment = new HashMap<String, String>();
-        List<String> loadedNativeLibraries = new ArrayList<String>();
-        return new VmInfo(vmPid, startTime, stopTime, javaVersion, javaHome, mainClass, commandLine, vmName, vmInfo, vmVersion, vmArguments, properties, environment, loadedNativeLibraries);
-    }
-
-    @Override
-    public DiscreteTimeData<Double>[] getCpuLoad() {
-        List<DiscreteTimeData<Double>> cpuData = new ArrayList<DiscreteTimeData<Double>>();
-
-        long currentTime = System.currentTimeMillis();
-        long oneMinute = 1000 * 60;
-
-        cpuData.add(new DiscreteTimeData<Double>(currentTime, r.nextDouble()));
-        cpuData.add(new DiscreteTimeData<Double>(currentTime - 1 * oneMinute, r.nextDouble()));
-        cpuData.add(new DiscreteTimeData<Double>(currentTime - 2 * oneMinute, r.nextDouble()));
-        cpuData.add(new DiscreteTimeData<Double>(currentTime - 3 * oneMinute, r.nextDouble()));
-        cpuData.add(new DiscreteTimeData<Double>(currentTime - 4 * oneMinute, r.nextDouble()));
-        cpuData.add(new DiscreteTimeData<Double>(currentTime - 5 * oneMinute, r.nextDouble()));
-        cpuData.add(new DiscreteTimeData<Double>(currentTime - 6 * oneMinute, r.nextDouble()));
-
-        return (DiscreteTimeData<Double>[]) cpuData.toArray(new DiscreteTimeData<?>[0]);
-    }
-
-    @Override
-    public DiscreteTimeData<Long>[] getMemoryUsage(MemoryType type) {
-        List<DiscreteTimeData<Long>> data = new ArrayList<DiscreteTimeData<Long>>();
-
-        long currentTime = System.currentTimeMillis();
-        long oneMinute = 1000 * 60;
-
-        data.add(new DiscreteTimeData<Long>(currentTime, r.nextLong()));
-        data.add(new DiscreteTimeData<Long>(currentTime - 1 * oneMinute, r.nextLong()));
-        data.add(new DiscreteTimeData<Long>(currentTime - 2 * oneMinute, r.nextLong()));
-        data.add(new DiscreteTimeData<Long>(currentTime - 3 * oneMinute, r.nextLong()));
-        data.add(new DiscreteTimeData<Long>(currentTime - 4 * oneMinute, r.nextLong()));
-        data.add(new DiscreteTimeData<Long>(currentTime - 5 * oneMinute, r.nextLong()));
-        data.add(new DiscreteTimeData<Long>(currentTime - 6 * oneMinute, r.nextLong()));
-        data.add(new DiscreteTimeData<Long>(currentTime - 7 * oneMinute, r.nextLong()));
-        data.add(new DiscreteTimeData<Long>(currentTime - 8 * oneMinute, r.nextLong()));
-
-        return (DiscreteTimeData<Long>[]) data.toArray(new DiscreteTimeData<?>[0]);
-    }
-
-    @Override
-    public MemoryType[] getMemoryTypesToDisplay() {
-        return toDisplay.toArray(new MemoryType[0]);
-    }
-
-    @Override
-    public boolean isMemoryTypeDisplayed(MemoryType type) {
-        return toDisplay.contains(type);
-    }
-
-    @Override
-    public void setDisplayMemoryType(MemoryType type, boolean selected) {
-        if (selected) {
-            if (!toDisplay.contains(type)) {
-                toDisplay.add(type);
-            }
-        } else {
-            toDisplay.remove(type);
-        }
-
-    }
-
-    @Override
-    public String[] getCollectorNames() {
-        return new String[] { "PSScavenge", "PSMarkSweep" };
-    }
-
-    @Override
-    public DiscreteTimeData<Long>[] getCollectorRunTime(String collectorName) {
-        List<DiscreteTimeData<Long>> data = new ArrayList<DiscreteTimeData<Long>>();
-
-        long last = 2;
-        data.add(new DiscreteTimeData<Long>(100000, (last = last + r.nextInt(10))));
-        data.add(new DiscreteTimeData<Long>(100010, (last = last + r.nextInt(10))));
-        data.add(new DiscreteTimeData<Long>(100020, (last = last + r.nextInt(10))));
-        data.add(new DiscreteTimeData<Long>(100030, (last = last + r.nextInt(10))));
-        data.add(new DiscreteTimeData<Long>(100040, (last = last + r.nextInt(10))));
-        data.add(new DiscreteTimeData<Long>(100050, (last = last + r.nextInt(10))));
-        data.add(new DiscreteTimeData<Long>(100060, (last = last + r.nextInt(10))));
-        data.add(new DiscreteTimeData<Long>(100070, (last = last + r.nextInt(10))));
-        data.add(new DiscreteTimeData<Long>(100080, (last = last + r.nextInt(10))));
-        data.add(new DiscreteTimeData<Long>(100090, (last = last + r.nextInt(10))));
-        data.add(new DiscreteTimeData<Long>(100110, (last = last + r.nextInt(10))));
-
-        return (DiscreteTimeData<Long>[]) data.toArray(new DiscreteTimeData<?>[0]);
-    }
-
-    @Override
-    public String getCollectorGeneration(String collectorName) {
-        if (collectorName.equals("PSScavenge")) {
-            return _("YOUNG_GEN");
-        } else if (collectorName.equals("PSMarkSweep")) {
-            return _("OLD_GEN");
-        }
-        return ("UNKNOWN_GEN");
-    }
-
-    @Override
-    public VmMemoryStat getLatestMemoryInfo() {
-        long timestamp = -1;
-        List<Generation> generations = new ArrayList<Generation>();
-
-        Generation youngGen = new Generation();
-        youngGen.name = "eden";
-        generations.add(youngGen);
-
-        List<Space> youngSpaces = new ArrayList<Space>();
-
-        Space eden = new Space();
-        eden.name = _("EDEN_GEN");
-        eden.used = 100;
-        eden.capacity = 200;
-        eden.maxCapacity = 300;
-        youngSpaces.add(eden);
-
-        Space s0 = new Space();
-        s0.name = _("S0_GEN");
-        s0.used = 100;
-        s0.capacity = 200;
-        s0.maxCapacity = 400;
-        youngSpaces.add(s0);
-
-        Space s1 = new Space();
-        s1.name = _("S1_GEN");
-        s1.used = 150;
-        s1.capacity = 200;
-        s1.maxCapacity = 400;
-        youngSpaces.add(s1);
-
-        youngGen.spaces = youngSpaces;
-
-        Generation oldGen = new Generation();
-        generations.add(oldGen);
-
-        Space oldSpace = new Space();
-        oldSpace.name = _("OLD_GEN");
-        oldSpace.used = 400;
-        oldSpace.capacity = 500;
-        oldSpace.maxCapacity = 600;
-
-        oldGen.spaces = Arrays.asList(new Space[] { oldSpace });
-
-        Generation permGen = new Generation();
-        generations.add(permGen);
-
-        Space permSpace = new Space();
-        permSpace.name = _("PERM_GEN");
-        permSpace.used = 50;
-        permSpace.capacity = 200;
-        permSpace.maxCapacity = 200;
-
-        permGen.spaces = Arrays.asList(new Space[] { permSpace });
-
-        VmMemoryStat stat = new VmMemoryStat(timestamp, 0, generations);
-        return stat;
-    }
-
-    @Override
-    public void start() {
-        // no-op
-    }
-
-    @Override
-    public void stop() {
-        // no-op
-    }
-
-}
--- a/src/com/redhat/thermostat/client/DummyUiFacadeFactory.java	Fri Jan 27 11:46:45 2012 -0500
+++ /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;
-
-public class DummyUiFacadeFactory implements UiFacadeFactory {
-
-    private final DummyFacade dummyFacade;
-
-    public DummyUiFacadeFactory() {
-        dummyFacade = new DummyFacade();
-    }
-
-    @Override
-    public MainWindowFacade getMainWindow() {
-        return dummyFacade;
-    }
-
-    @Override
-    public SummaryPanelFacade getSummaryPanel() {
-        return dummyFacade;
-    }
-
-    @Override
-    public HostPanelFacade getHostPanel(HostRef ref) {
-        return dummyFacade;
-    }
-
-    @Override
-    public VmPanelFacade getVmPanel(VmRef ref) {
-        return dummyFacade;
-    }
-
-}
--- a/src/com/redhat/thermostat/client/HostPanelFacade.java	Fri Jan 27 11:46:45 2012 -0500
+++ b/src/com/redhat/thermostat/client/HostPanelFacade.java	Mon Jan 30 13:42:10 2012 -0500
@@ -36,14 +36,9 @@
 
 package com.redhat.thermostat.client;
 
-import com.redhat.thermostat.common.HostInfo;
-import com.redhat.thermostat.common.NetworkInfo;
+import javax.swing.table.TableModel;
 
-public interface HostPanelFacade {
-    public HostInfo getHostInfo();
-
-    public NetworkInfo getNetworkInfo();
-
+public interface HostPanelFacade extends AsyncUiFacade {
     public DiscreteTimeData<Double>[] getCpuLoad();
 
     public DiscreteTimeData<Long>[] getMemoryUsage(MemoryType type);
@@ -54,4 +49,18 @@
 
     public void setDisplayMemoryType(MemoryType type, boolean selected);
 
+    public ChangeableText getHostName();
+
+    public ChangeableText getCpuModel();
+
+    public ChangeableText getCpuCount();
+
+    public ChangeableText getTotalMemory();
+
+    public ChangeableText getOsName();
+
+    public ChangeableText getOsKernel();
+
+    public TableModel getNetworkTableModel();
+
 }
--- a/src/com/redhat/thermostat/client/HostPanelFacadeImpl.java	Fri Jan 27 11:46:45 2012 -0500
+++ b/src/com/redhat/thermostat/client/HostPanelFacadeImpl.java	Mon Jan 30 13:42:10 2012 -0500
@@ -36,29 +36,51 @@
 
 package com.redhat.thermostat.client;
 
+import static com.redhat.thermostat.client.Translate._;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.Vector;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+import javax.swing.SwingWorker;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableModel;
 
 import com.mongodb.BasicDBObject;
 import com.mongodb.DB;
 import com.mongodb.DBCollection;
 import com.mongodb.DBCursor;
 import com.mongodb.DBObject;
-import com.redhat.thermostat.common.HostInfo;
 import com.redhat.thermostat.common.NetworkInfo;
 import com.redhat.thermostat.common.NetworkInterfaceInfo;
 
 public class HostPanelFacadeImpl implements HostPanelFacade {
 
-    private HostRef agent;
-    private DB db;
-    private DBCollection hostInfoCollection;
-    private DBCollection networkInfoCollection;
-    private DBCollection cpuStatsCollection;
-    private DBCollection memoryStatsCollection;
+    private final HostRef agent;
+    private final DB db;
+    private final DBCollection hostInfoCollection;
+    private final DBCollection networkInfoCollection;
+    private final DBCollection cpuStatsCollection;
+    private final DBCollection memoryStatsCollection;
+
+    private final ChangeableText hostName = new ChangeableText("");
+    private final ChangeableText osName = new ChangeableText("");
+    private final ChangeableText osKernel = new ChangeableText("");
+    private final ChangeableText cpuModel = new ChangeableText("");
+    private final ChangeableText cpuCount = new ChangeableText("");
+    private final ChangeableText memoryTotal = new ChangeableText("");
+    private final DefaultTableModel networkTableModel = new DefaultTableModel();
+    private final Vector<String> networkTableColumnVector;
+
+    private final Timer backgroundUpdateTimer = new Timer();
 
     private Set<MemoryType> toDisplay = new HashSet<MemoryType>();
 
@@ -71,27 +93,69 @@
         cpuStatsCollection = db.getCollection("cpu-stats");
         memoryStatsCollection = db.getCollection("memory-stats");
 
+        networkTableColumnVector = new Vector<String>();
+        networkTableColumnVector.add(_("NETWORK_INTERFACE_COLUMN"));
+        networkTableColumnVector.add(_("NETWORK_IPV4_COLUMN"));
+        networkTableColumnVector.add(_("NETWORK_IPV6_COLUMN"));
+
         toDisplay.addAll(Arrays.asList(MemoryType.values()));
     }
 
-    /*
-     * Host-related methods
-     */
+    @Override
+    public void start() {
+        backgroundUpdateTimer.scheduleAtFixedRate(new TimerTask() {
+            @Override
+            public void run() {
+                DBObject hostInfo = hostInfoCollection.findOne(new BasicDBObject("agent-id", agent.getAgentId()));
+                hostName.setText((String) hostInfo.get("hostname"));
+                osName.setText((String) hostInfo.get("os_name"));
+                osKernel.setText((String) hostInfo.get("os_kernel"));
+                cpuModel.setText((String) hostInfo.get("cpu_model"));
+                cpuCount.setText((String) hostInfo.get("cpu_num"));
+                memoryTotal.setText((String) hostInfo.get("memory_total"));
+
+                doNetworkTableUpdateAsync();
+            }
+
+        }, 0, TimeUnit.SECONDS.toMillis(5));
+    }
 
     @Override
-    public HostInfo getHostInfo() {
-        DBObject hostInfo = hostInfoCollection.findOne(new BasicDBObject("agent-id", agent.getAgentId()));
-        String hostName = (String) hostInfo.get("hostname");
-        String osName = (String) hostInfo.get("os_name");
-        String osKernel = (String) hostInfo.get("os_kernel");
-        String cpuModel = (String) hostInfo.get("cpu_model");
-        String cpuCount = (String) hostInfo.get("cpu_num");
-        String memoryTotal = (String) hostInfo.get("memory_total");
-        return new HostInfo(hostName, osName, osKernel, cpuModel, Integer.valueOf(cpuCount), Long.valueOf(memoryTotal));
+    public void stop() {
+        backgroundUpdateTimer.cancel();
     }
 
     @Override
-    public NetworkInfo getNetworkInfo() {
+    public ChangeableText getHostName() {
+        return hostName;
+    }
+
+    @Override
+    public ChangeableText getCpuCount() {
+        return cpuCount;
+    }
+
+    @Override
+    public ChangeableText getCpuModel() {
+        return cpuModel;
+    }
+
+    @Override
+    public ChangeableText getOsKernel() {
+        return osKernel;
+    }
+
+    @Override
+    public ChangeableText getOsName() {
+        return osName;
+    }
+
+    @Override
+    public ChangeableText getTotalMemory() {
+        return memoryTotal;
+    }
+
+    private NetworkInfo getNetworkInfo() {
         NetworkInfo network = new NetworkInfo();
         DBCursor cursor = networkInfoCollection.find(new BasicDBObject("agent-id", agent.getAgentId()));
         while (cursor.hasNext()) {
@@ -109,6 +173,52 @@
         return network;
     }
 
+    private void doNetworkTableUpdateAsync() {
+        new NetworkTableModelUpdater(this).execute();
+    }
+
+    private static class NetworkTableModelUpdater extends SwingWorker<NetworkInfo, Void> {
+
+        private HostPanelFacadeImpl facade;
+
+        public NetworkTableModelUpdater(HostPanelFacadeImpl facade) {
+            this.facade = facade;
+        }
+
+        @Override
+        protected NetworkInfo doInBackground() throws Exception {
+            return facade.getNetworkInfo();
+        }
+
+        @Override
+        protected void done() {
+            Vector<Vector<String>> data = new Vector<Vector<String>>();
+
+            NetworkInfo networkInfo;
+            try {
+                networkInfo = get();
+                for (Iterator<NetworkInterfaceInfo> iter = networkInfo.getInterfacesIterator(); iter.hasNext();) {
+                    NetworkInterfaceInfo networkIfaceInfo = iter.next();
+                    String ifaceName = networkIfaceInfo.getInterfaceName();
+                    String ipv4 = networkIfaceInfo.getIp4Addr();
+                    String ipv6 = networkIfaceInfo.getIp6Addr();
+                    data.add(new Vector<String>(Arrays.asList(new String[] {ifaceName, ipv4, ipv6})));
+                }
+                facade.networkTableModel.setDataVector(data, facade.networkTableColumnVector);
+
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            } catch (ExecutionException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @Override
+    public TableModel getNetworkTableModel() {
+        return networkTableModel;
+    }
+
     @Override
     public DiscreteTimeData<Double>[] getCpuLoad() {
         List<DiscreteTimeData<Double>> load = new ArrayList<DiscreteTimeData<Double>>();
@@ -166,6 +276,4 @@
         }
     }
 
-
-
 }
--- a/src/com/redhat/thermostat/client/Main.java	Fri Jan 27 11:46:45 2012 -0500
+++ b/src/com/redhat/thermostat/client/Main.java	Mon Jan 30 13:42:10 2012 -0500
@@ -111,11 +111,7 @@
         connection.connect();
         connection.removeListener(connectionListener);
 
-        if (arguments.useDummyDataSource()) {
-            uiFacadeFactory = new DummyUiFacadeFactory();
-        } else {
-            uiFacadeFactory = new UiFacadeFactoryImpl((MongoConnection) connection);
-        }
+        uiFacadeFactory = new UiFacadeFactoryImpl((MongoConnection) connection);
 
         MainWindow gui = new MainWindow(uiFacadeFactory);
         gui.pack();
--- a/src/com/redhat/thermostat/client/MainWindowFacade.java	Fri Jan 27 11:46:45 2012 -0500
+++ b/src/com/redhat/thermostat/client/MainWindowFacade.java	Mon Jan 30 13:42:10 2012 -0500
@@ -38,11 +38,7 @@
 
 import javax.swing.tree.TreeModel;
 
-public interface MainWindowFacade {
-
-    public void start();
-
-    public void stop();
+public interface MainWindowFacade extends AsyncUiFacade {
 
     public HostRef[] getHosts();
 
--- a/src/com/redhat/thermostat/client/MainWindowFacadeImpl.java	Fri Jan 27 11:46:45 2012 -0500
+++ b/src/com/redhat/thermostat/client/MainWindowFacadeImpl.java	Mon Jan 30 13:42:10 2012 -0500
@@ -68,36 +68,33 @@
 
     private static final Logger logger = LoggingUtils.getLogger(MainWindowFacadeImpl.class);
 
+    private final DB db;
+    private final DBCollection agentConfigCollection;
+    private final DBCollection hostInfoCollection;
+    private final DBCollection vmInfoCollection;
+
     private final DefaultMutableTreeNode publishedRoot = new DefaultMutableTreeNode(_("MAIN_WINDOW_TREE_ROOT_NAME"));
     private final DefaultTreeModel publishedTreeModel = new DefaultTreeModel(publishedRoot);
 
-    private DB db;
-    private DBCollection agentConfigCollection;
-    private DBCollection hostInfoCollection;
-    private DBCollection vmInfoCollection;
-
     private String filterText;
 
-    private Timer backgroundUpdater;
+    private final Timer backgroundUpdater = new Timer();
 
     public MainWindowFacadeImpl(DB db) {
         this.db = db;
         this.agentConfigCollection = db.getCollection("agent-config");
         this.hostInfoCollection = db.getCollection("host-info");
         this.vmInfoCollection = db.getCollection("vm-info");
-
     }
 
     @Override
     public void start() {
-        backgroundUpdater = new Timer();
         backgroundUpdater.scheduleAtFixedRate(new TimerTask() {
             @Override
             public void run() {
                 doUpdateTreeAsync();
             }
         }, 0, TimeUnit.SECONDS.toMillis(10));
-
     }
 
     @Override
--- a/src/com/redhat/thermostat/client/SummaryPanelFacade.java	Fri Jan 27 11:46:45 2012 -0500
+++ b/src/com/redhat/thermostat/client/SummaryPanelFacade.java	Mon Jan 30 13:42:10 2012 -0500
@@ -38,11 +38,11 @@
 
 import java.util.List;
 
-public interface SummaryPanelFacade {
+public interface SummaryPanelFacade extends AsyncUiFacade {
 
-    public long getTotalConnectedVms();
+    public ChangeableText getTotalConnectedVms();
 
-    public long getTotalConnectedAgents();
+    public ChangeableText getTotalConnectedAgents();
 
     public List<String> getIssues();
 
--- a/src/com/redhat/thermostat/client/SummaryPanelFacadeImpl.java	Fri Jan 27 11:46:45 2012 -0500
+++ b/src/com/redhat/thermostat/client/SummaryPanelFacadeImpl.java	Mon Jan 30 13:42:10 2012 -0500
@@ -38,30 +38,57 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.TimeUnit;
 
 import com.mongodb.DB;
 import com.mongodb.DBCollection;
 
 public class SummaryPanelFacadeImpl implements SummaryPanelFacade {
 
-    private DB db;
-    private DBCollection agentConfigCollection;
-    private DBCollection vmInfoCollection;
+    private final DB db;
+    private final DBCollection agentConfigCollection;
+    private final DBCollection vmInfoCollection;
+
+    private final ChangeableText connectedAgentText;
+    private final ChangeableText connectedVmText;
+
+    private final Timer backgroundUpdateTimer = new Timer();
 
     public SummaryPanelFacadeImpl(DB db) {
         this.db = db;
         this.agentConfigCollection = db.getCollection("agent-config");
         this.vmInfoCollection = db.getCollection("vm-info");
+
+        this.connectedVmText = new ChangeableText("");
+        this.connectedAgentText = new ChangeableText("");
     }
 
     @Override
-    public long getTotalConnectedVms() {
-        return vmInfoCollection.getCount();
+    public void start() {
+        backgroundUpdateTimer.scheduleAtFixedRate(new TimerTask() {
+            @Override
+            public void run() {
+                connectedVmText.setText(String.valueOf(vmInfoCollection.getCount()));
+                connectedAgentText.setText(String.valueOf(agentConfigCollection.getCount()));
+            }
+        }, 0, TimeUnit.SECONDS.toMillis(10));
     }
 
     @Override
-    public long getTotalConnectedAgents() {
-        return agentConfigCollection.getCount();
+    public void stop() {
+        backgroundUpdateTimer.cancel();
+    }
+
+    @Override
+    public ChangeableText getTotalConnectedVms() {
+        return connectedVmText;
+    }
+
+    @Override
+    public ChangeableText getTotalConnectedAgents() {
+        return connectedAgentText;
     }
 
     @Override
--- a/src/com/redhat/thermostat/client/VmPanelFacade.java	Fri Jan 27 11:46:45 2012 -0500
+++ b/src/com/redhat/thermostat/client/VmPanelFacade.java	Mon Jan 30 13:42:10 2012 -0500
@@ -36,19 +36,13 @@
 
 package com.redhat.thermostat.client;
 
-import com.redhat.thermostat.common.VmInfo;
 import com.redhat.thermostat.common.VmMemoryStat;
 
 /**
  * Represents information specific to a JVM running on a host somewhere. This is
  * used to populate the UI for a VM's information.
  */
-public interface VmPanelFacade {
-
-    /**
-     * @return generic overview information about a vm
-     */
-    public VmInfo getVmInfo();
+public interface VmPanelFacade extends AsyncUiFacade {
 
     /**
      * @return names of the garbage collectors that are operating
@@ -65,4 +59,22 @@
 
     public VmMemoryStat getLatestMemoryInfo();
 
+    public ChangeableText getVmPid();
+
+    public ChangeableText getMainClass();
+
+    public ChangeableText getJavaCommandLine();
+
+    public ChangeableText getJavaVersion();
+
+    public ChangeableText getVmName();
+
+    public ChangeableText getVmVersion();
+
+    public ChangeableText getStartTimeStamp();
+
+    public ChangeableText getStopTimeStamp();
+
+    public ChangeableText getVmNameAndVersion();
+
 }
--- a/src/com/redhat/thermostat/client/VmPanelFacadeImpl.java	Fri Jan 27 11:46:45 2012 -0500
+++ b/src/com/redhat/thermostat/client/VmPanelFacadeImpl.java	Mon Jan 30 13:42:10 2012 -0500
@@ -37,28 +37,48 @@
 package com.redhat.thermostat.client;
 
 import static com.redhat.thermostat.client.Translate._;
+
+import java.text.DateFormat;
 import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Date;
 import java.util.List;
-import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.TimeUnit;
 
 import com.mongodb.BasicDBObject;
 import com.mongodb.DB;
 import com.mongodb.DBCollection;
 import com.mongodb.DBCursor;
 import com.mongodb.DBObject;
-import com.redhat.thermostat.common.VmInfo;
 import com.redhat.thermostat.common.VmMemoryStat;
 import com.redhat.thermostat.common.VmMemoryStat.Generation;
 import com.redhat.thermostat.common.VmMemoryStat.Space;
 
 public class VmPanelFacadeImpl implements VmPanelFacade {
 
-    private VmRef ref;
-    private DB db;
-    private DBCollection vmInfoCollection;
-    private DBCollection vmGcStatsCollection;
-    private DBCollection vmMemoryStatsCollection;
+    private final VmRef ref;
+    private final DB db;
+    private final DBCollection vmInfoCollection;
+    private final DBCollection vmGcStatsCollection;
+    private final DBCollection vmMemoryStatsCollection;
+
+    private final ChangeableText vmPid = new ChangeableText("");
+    private final ChangeableText startTime = new ChangeableText("");
+    private final ChangeableText stopTime = new ChangeableText("");
+    private final ChangeableText javaVersion = new ChangeableText("");
+    private final ChangeableText javaHome = new ChangeableText("");
+    private final ChangeableText mainClass = new ChangeableText("");
+    private final ChangeableText commandLine = new ChangeableText("");
+    private final ChangeableText vmName = new ChangeableText("");
+    private final ChangeableText vmInfo = new ChangeableText("");
+    private final ChangeableText vmVersion = new ChangeableText("");
+    private final ChangeableText vmArguments = new ChangeableText("");
+    private final ChangeableText vmNameAndVersion = new ChangeableText("");
+
+    private final Timer timer = new Timer();
+
+    private final DateFormat vmRunningTimeFormat;
 
     private VmMemoryStat cached;
 
@@ -69,35 +89,92 @@
         vmGcStatsCollection = db.getCollection("vm-gc-stats");
         vmMemoryStatsCollection = db.getCollection("vm-memory-stats");
 
+        vmRunningTimeFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.FULL);
+    }
+
+    @Override
+    public void start() {
+        timer.scheduleAtFixedRate(new TimerTask() {
+            @Override
+            public void run() {
+                BasicDBObject queryObject = new BasicDBObject();
+                queryObject.put("agent-id", ref.getAgent().getAgentId());
+                queryObject.put("vm-id", ref.getId());
+                DBObject vmInfoObject = vmInfoCollection.findOne(queryObject);
+                vmPid.setText((String) vmInfoObject.get("vm-pid"));
+                long actualStartTime = Long.valueOf((String) vmInfoObject.get("start-time"));
+                startTime.setText(vmRunningTimeFormat.format(new Date(actualStartTime)));
+                long actualStopTime = Long.valueOf((String) vmInfoObject.get("stop-time"));
+                if (actualStopTime >= actualStartTime) {
+                    // Only show a stop time if we have actually stopped.
+                    stopTime.setText(vmRunningTimeFormat.format(new Date(actualStopTime)));
+                } else {
+                    stopTime.setText(_("VM_INFO_RUNNING"));
+                }
+                javaVersion.setText((String) vmInfoObject.get("runtime-version"));
+                javaHome.setText((String) vmInfoObject.get("java-home"));
+                mainClass.setText((String) vmInfoObject.get("main-class"));
+                commandLine.setText((String) vmInfoObject.get("command-line"));
+                String actualVmName = (String) vmInfoObject.get("vm-name");
+                vmName.setText(actualVmName);
+                vmInfo.setText((String) vmInfoObject.get("vm-info"));
+                String actualVmVersion = (String) vmInfoObject.get("vm-version");
+                vmVersion.setText(actualVmVersion);
+                vmArguments.setText((String) vmInfoObject.get("vm-arguments"));
+                vmNameAndVersion.setText(_("VM_INFO_VM_NAME_AND_VERSION", actualVmName, actualVmVersion));
+            }
+        }, 0, TimeUnit.SECONDS.toMillis(5));
+
     }
 
     @Override
-    public VmInfo getVmInfo() {
-        BasicDBObject queryObject = new BasicDBObject();
-        queryObject.put("agent-id", ref.getAgent().getAgentId());
-        queryObject.put("vm-id", ref.getId());
-        DBObject vmInfoObject = vmInfoCollection.findOne(queryObject);
-        int vmPid = Integer.valueOf((String) vmInfoObject.get("vm-pid"));
-        long startTime = Long.valueOf((String) vmInfoObject.get("start-time"));
-        long stopTime = Long.valueOf((String) vmInfoObject.get("stop-time"));
-        String javaVersion = (String) vmInfoObject.get("runtime-version");
-        String javaHome = (String) vmInfoObject.get("java-home");
-        String mainClass = (String) vmInfoObject.get("main-class");
-        String commandLine = (String) vmInfoObject.get("command-line");
-        String vmName = (String) vmInfoObject.get("vm-name");
-        String vmInfo = (String) vmInfoObject.get("vm-info");
-        String vmVersion = (String) vmInfoObject.get("vm-version");
-        String vmArguments = (String) vmInfoObject.get("vm-arguments");
-        // TODO fill in these
-        Map<String, String> properties = new HashMap<String, String>();
-        Map<String, String> environment = new HashMap<String, String>();
-        List<String> loadedNativeLibraries = new ArrayList<String>();
-        return new VmInfo(vmPid, startTime, stopTime,
-                javaVersion, javaHome,
-                mainClass, commandLine,
-                vmName, vmInfo, vmVersion, vmArguments,
-                properties, environment, loadedNativeLibraries);
+    public void stop() {
+        timer.cancel();
+    }
+
+    @Override
+    public ChangeableText getVmPid() {
+        return vmPid;
+    }
+
+    @Override
+    public ChangeableText getJavaCommandLine() {
+        return commandLine;
+    }
+
+    @Override
+    public ChangeableText getJavaVersion() {
+        return javaVersion;
+    }
+
+    @Override
+    public ChangeableText getMainClass() {
+        return mainClass;
+    }
 
+    @Override
+    public ChangeableText getStartTimeStamp() {
+        return startTime;
+    }
+
+    @Override
+    public ChangeableText getStopTimeStamp() {
+        return stopTime;
+    }
+
+    @Override
+    public ChangeableText getVmNameAndVersion() {
+        return vmNameAndVersion;
+    }
+
+    @Override
+    public ChangeableText getVmName() {
+        return vmName;
+    }
+
+    @Override
+    public ChangeableText getVmVersion() {
+        return vmVersion;
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/redhat/thermostat/client/ui/AsyncFacadeManager.java	Mon Jan 30 13:42:10 2012 -0500
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.ui;
+
+import java.awt.Component;
+
+import com.redhat.thermostat.client.AsyncUiFacade;
+
+public class AsyncFacadeManager extends ComponentVisibleListener {
+
+    private AsyncUiFacade facade;
+
+    public AsyncFacadeManager(AsyncUiFacade facade) {
+        this.facade = facade;
+    }
+
+    @Override
+    public void componentHidden(Component component) {
+        facade.stop();
+    }
+
+    @Override
+    public void componentShown(Component component) {
+        facade.start();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/redhat/thermostat/client/ui/ComponentVisibleListener.java	Mon Jan 30 13:42:10 2012 -0500
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2012 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.client.ui;
+
+import java.awt.Component;
+import java.awt.event.HierarchyEvent;
+import java.awt.event.HierarchyListener;
+
+public abstract class ComponentVisibleListener implements HierarchyListener {
+    @Override
+    public void hierarchyChanged(HierarchyEvent e) {
+        if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0)  {
+            if (e.getComponent().isShowing()) {
+                componentShown(e.getComponent());
+            } else {
+                componentHidden(e.getComponent());
+            }
+        }
+
+    }
+
+    public abstract void componentShown(Component component);
+
+    public abstract void componentHidden(Component component);
+
+}
--- a/src/com/redhat/thermostat/client/ui/HostPanel.java	Fri Jan 27 11:46:45 2012 -0500
+++ b/src/com/redhat/thermostat/client/ui/HostPanel.java	Mon Jan 30 13:42:10 2012 -0500
@@ -39,24 +39,19 @@
 import static com.redhat.thermostat.client.Translate._;
 
 import java.awt.BorderLayout;
-import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 
 import javax.swing.AbstractButton;
 import javax.swing.JCheckBox;
 import javax.swing.JPanel;
-import javax.swing.JScrollPane;
 import javax.swing.JTabbedPane;
 import javax.swing.JTable;
-import javax.swing.table.DefaultTableModel;
-import javax.swing.table.TableModel;
 
 import org.jfree.chart.ChartFactory;
 import org.jfree.chart.ChartPanel;
@@ -74,8 +69,6 @@
 import com.redhat.thermostat.client.ui.SimpleTable.Section;
 import com.redhat.thermostat.client.ui.SimpleTable.TableEntry;
 import com.redhat.thermostat.client.ui.SimpleTable.Value;
-import com.redhat.thermostat.common.HostInfo;
-import com.redhat.thermostat.common.NetworkInterfaceInfo;
 
 public class HostPanel extends JPanel {
 
@@ -87,12 +80,12 @@
     private static final long serialVersionUID = 4835316442841009133L;
 
     private final HostPanelFacade facade;
-    private final HostInfo hostInfo;
 
-    public HostPanel(HostPanelFacade facade) {
+    public HostPanel(final HostPanelFacade facade) {
         this.facade = facade;
-        this.hostInfo = facade.getHostInfo();
+
         init();
+        addHierarchyListener(new AsyncFacadeManager(facade));
     }
 
     private void init() {
@@ -119,31 +112,20 @@
         Section basics = new Section(_("HOST_OVERVIEW_SECTION_BASICS"));
         allSections.add(basics);
 
-        entry = new TableEntry(_("HOST_INFO_HOSTNAME"), hostInfo.getHostname());
+        entry = new TableEntry(_("HOST_INFO_HOSTNAME"), facade.getHostName());
         basics.add(entry);
 
         Section hardware = new Section(_("HOST_OVERVIEW_SECTION_HARDWARE"));
         allSections.add(hardware);
 
-        entry = new TableEntry(_("HOST_INFO_CPU_MODEL"), hostInfo.getCpuModel());
+        entry = new TableEntry(_("HOST_INFO_CPU_MODEL"), facade.getCpuModel());
         hardware.add(entry);
-        entry = new TableEntry(_("HOST_INFO_CPU_COUNT"), String.valueOf(hostInfo.getCpuCount()));
+        entry = new TableEntry(_("HOST_INFO_CPU_COUNT"), facade.getCpuCount());
         hardware.add(entry);
-        entry = new TableEntry(_("HOST_INFO_MEMORY_TOTAL"), String.valueOf(hostInfo.getTotalMemory()));
+        entry = new TableEntry(_("HOST_INFO_MEMORY_TOTAL"), facade.getTotalMemory());
         hardware.add(entry);
 
-        DefaultTableModel networkTableModel = new DefaultTableModel();
-        networkTableModel.addColumn(_("NETWORK_INTERFACE_COLUMN"));
-        networkTableModel.addColumn(_("NETWORK_IPV4_COLUMN"));
-        networkTableModel.addColumn(_("NETWORK_IPV6_COLUMN"));
-        for (Iterator<NetworkInterfaceInfo> iter = facade.getNetworkInfo().getInterfacesIterator(); iter.hasNext();) {
-            NetworkInterfaceInfo networkInfo = iter.next();
-            String ifaceName = networkInfo.getInterfaceName();
-            String ipv4 = networkInfo.getIp4Addr();
-            String ipv6 = networkInfo.getIp6Addr();
-            networkTableModel.addRow(new Object[] {ifaceName, ipv4, ipv6});
-        }
-        JTable networkTable = new JTable(networkTableModel);
+        JTable networkTable = new JTable(facade.getNetworkTableModel());
 
         JPanel networkPanel = new JPanel(new BorderLayout());
         networkPanel.add(networkTable.getTableHeader(), BorderLayout.PAGE_START);
@@ -155,12 +137,13 @@
         Section software = new Section(_("HOST_OVERVIEW_SECTION_SOFTWARE"));
         allSections.add(software);
 
-        entry = new TableEntry(_("HOST_INFO_OS_NAME"), hostInfo.getOsName());
+        entry = new TableEntry(_("HOST_INFO_OS_NAME"), facade.getOsName());
         software.add(entry);
-        entry = new TableEntry(_("HOST_INFO_OS_KERNEL"), hostInfo.getOsKernel());
+        entry = new TableEntry(_("HOST_INFO_OS_KERNEL"), facade.getOsKernel());
         software.add(entry);
 
-        JPanel table = SimpleTable.createTable(allSections);
+        SimpleTable simpleTable = new SimpleTable();
+        JPanel table = simpleTable.createTable(allSections);
         table.setBorder(Components.smallBorder());
         return table;
     }
@@ -181,12 +164,13 @@
         allSections.add(cpuBasics);
 
         TableEntry entry;
-        entry = new TableEntry(_("HOST_INFO_CPU_MODEL"), hostInfo.getCpuModel());
+        entry = new TableEntry(_("HOST_INFO_CPU_MODEL"), facade.getCpuModel());
         cpuBasics.add(entry);
-        entry = new TableEntry(_("HOST_INFO_CPU_COUNT"), String.valueOf(hostInfo.getCpuCount()));
+        entry = new TableEntry(_("HOST_INFO_CPU_COUNT"), facade.getCpuCount());
         cpuBasics.add(entry);
 
-        JPanel table = SimpleTable.createTable(allSections);
+        final SimpleTable simpleTable = new SimpleTable();
+        JPanel table = simpleTable.createTable(allSections);
         table.setBorder(Components.smallBorder());
         contentArea.add(table, c);
 
@@ -236,10 +220,11 @@
         allSections.add(memoryBasics);
 
         TableEntry entry;
-        entry = new TableEntry(_("HOST_INFO_MEMORY_TOTAL"), String.valueOf(hostInfo.getTotalMemory()));
+        entry = new TableEntry(_("HOST_INFO_MEMORY_TOTAL"), facade.getTotalMemory());
         memoryBasics.add(entry);
 
-        JPanel table = SimpleTable.createTable(allSections);
+        SimpleTable simpleTable = new SimpleTable();
+        JPanel table = simpleTable.createTable(allSections);
         table.setBorder(Components.smallBorder());
         contentArea.add(table, BorderLayout.PAGE_START);
 
--- a/src/com/redhat/thermostat/client/ui/SimpleTable.java	Fri Jan 27 11:46:45 2012 -0500
+++ b/src/com/redhat/thermostat/client/ui/SimpleTable.java	Mon Jan 30 13:42:10 2012 -0500
@@ -41,12 +41,23 @@
 import java.awt.GridBagLayout;
 import java.awt.Insets;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
 
 import javax.swing.Box;
+import javax.swing.JLabel;
 import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
 
-public class SimpleTable {
+import com.redhat.thermostat.client.ChangeableText;
+
+public class SimpleTable implements ChangeableText.TextListener {
+
+    Map<ChangeableText, Set<JLabel>> updateMap = new HashMap<ChangeableText, Set<JLabel>>();
 
     public static class Section {
         private final String sectionName;
@@ -81,7 +92,7 @@
         private final Key key;
         private final List<Value> values;
 
-        public TableEntry(String key, String value) {
+        public TableEntry(String key, ChangeableText value) {
             this(new Key(key), new Value(value));
         }
 
@@ -103,7 +114,6 @@
         public Value[] getValues() {
             return values.toArray(new Value[0]);
         }
-
     }
 
     public static class Key {
@@ -119,10 +129,14 @@
     }
 
     public static class Value {
-        private final String text;
+        private final ChangeableText text;
         private final Component actualComponent;
 
         public Value(String text) {
+            this(new ChangeableText(text));
+        }
+
+        public Value(ChangeableText text) {
             this.text = text;
             this.actualComponent = null;
         }
@@ -132,16 +146,16 @@
             this.text = null;
         }
 
-        public String getText() {
-            return text;
-        }
         public Component getComponent() {
             return actualComponent;
         }
 
+        public ChangeableText getChangeableText() {
+            return text;
+        }
     }
 
-    public static JPanel createTable(List<Section> sections) {
+    public JPanel createTable(List<Section> sections) {
         final int SECTION_TOP_GAP = 10;
         final int ROW_VERTICAL_GAP = 0;
         final int ROW_HORIZONTAL_GAP = 10;
@@ -177,7 +191,16 @@
 
                 for (Value value : tableEntry.getValues()) {
                     if (value.getComponent() == null) {
-                        container.add(Components.value(value.getText()), valueConstraints);
+                        ChangeableText text = value.getChangeableText();
+                        JLabel valueLabel = Components.value(text.getText());
+                        if (updateMap.containsKey(text)) {
+                            updateMap.get(text).add(valueLabel);
+                        } else {
+                            Set<JLabel> set = new HashSet<JLabel>();
+                            set.add(valueLabel);
+                            updateMap.put(text, set);
+                        }
+                        container.add(valueLabel, valueConstraints);
                     } else {
                         container.add(value.getComponent(), valueConstraints);
                     }
@@ -197,7 +220,54 @@
         Component filler = Box.createGlue();
         container.add(filler, glueConstraints);
 
+        container.addHierarchyListener(new ComponentVisibleListener() {
+            @Override
+            public void componentShown(Component c) {
+                updateAllValues();
+                addAllListeners();
+            }
+
+            @Override
+            public void componentHidden(Component c) {
+                removeAllListeners();
+            }
+        });
+
         return container;
     }
 
+
+    private void updateAllValues() {
+        for (Entry<ChangeableText, Set<JLabel>> entry: updateMap.entrySet()) {
+            for (JLabel label: entry.getValue()) {
+                label.setText(entry.getKey().getText());
+            }
+        }
+    }
+
+    @Override
+    public void textChanged(final ChangeableText text) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                String newValue = text.getText();
+                for (JLabel label: updateMap.get(text)) {
+                    label.setText(newValue);
+                }
+            }
+        });
+    }
+
+    public void addAllListeners() {
+        for (ChangeableText text : updateMap.keySet()) {
+            text.addListener(this);
+        }
+    }
+
+    public void removeAllListeners() {
+        for (ChangeableText text : updateMap.keySet()) {
+            text.removeListener(this);
+        }
+    }
+
 }
--- a/src/com/redhat/thermostat/client/ui/SummaryPanel.java	Fri Jan 27 11:46:45 2012 -0500
+++ b/src/com/redhat/thermostat/client/ui/SummaryPanel.java	Mon Jan 30 13:42:10 2012 -0500
@@ -43,7 +43,6 @@
 import java.util.List;
 
 import javax.swing.AbstractListModel;
-import javax.swing.JLabel;
 import javax.swing.JList;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
@@ -70,12 +69,13 @@
         Section summarySection = new Section(_("HOME_PANEL_SECTION_SUMMARY"));
         sections.add(summarySection);
 
-        entry = new TableEntry(_("HOME_PANEL_TOTAL_MACHINES"), String.valueOf(facade.getTotalConnectedAgents()));
+        entry = new TableEntry(_("HOME_PANEL_TOTAL_MACHINES"), facade.getTotalConnectedAgents());
         summarySection.add(entry);
-        entry = new TableEntry(_("HOME_PANEL_TOTAL_JVMS"), String.valueOf(facade.getTotalConnectedVms()));
+        entry = new TableEntry(_("HOME_PANEL_TOTAL_JVMS"), facade.getTotalConnectedVms());
         summarySection.add(entry);
 
-        JPanel summaryPanel = SimpleTable.createTable(sections);
+        SimpleTable simpleTable = new SimpleTable();
+        JPanel summaryPanel = simpleTable.createTable(sections);
         summaryPanel.setBorder(Components.smallBorder());
         add(summaryPanel, BorderLayout.CENTER);
 
@@ -83,6 +83,7 @@
         issuesPanel.setBorder(Components.smallBorder());
         add(issuesPanel, BorderLayout.PAGE_END);
 
+        addHierarchyListener(new AsyncFacadeManager(facade));
     }
 
     public JPanel createIssuesPanel() {
--- a/src/com/redhat/thermostat/client/ui/VmPanel.java	Fri Jan 27 11:46:45 2012 -0500
+++ b/src/com/redhat/thermostat/client/ui/VmPanel.java	Mon Jan 30 13:42:10 2012 -0500
@@ -42,11 +42,7 @@
 import java.awt.Component;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
-import java.text.DateFormat;
 import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
 import java.util.List;
 
 import javax.swing.JPanel;
@@ -65,7 +61,6 @@
 import com.redhat.thermostat.client.VmPanelFacade;
 import com.redhat.thermostat.client.ui.SimpleTable.Section;
 import com.redhat.thermostat.client.ui.SimpleTable.TableEntry;
-import com.redhat.thermostat.common.VmInfo;
 import com.redhat.thermostat.common.VmMemoryStat;
 import com.redhat.thermostat.common.VmMemoryStat.Generation;
 import com.redhat.thermostat.common.VmMemoryStat.Space;
@@ -76,12 +71,11 @@
 
     private final VmPanelFacade facade;
 
-    private final VmInfo vmInfo;
+    public VmPanel(final VmPanelFacade facade) {
+        this.facade = facade;
+        createUI();
 
-    public VmPanel(VmPanelFacade facade) {
-        this.facade = facade;
-        this.vmInfo = facade.getVmInfo();
-        createUI();
+        addHierarchyListener(new AsyncFacadeManager(facade));
     }
 
     public void createUI() {
@@ -110,34 +104,27 @@
         Section processSection = new Section(_("VM_INFO_SECTION_PROCESS"));
         allSections.add(processSection);
 
-        entry = new TableEntry(_("VM_INFO_PROCESS_ID"), String.valueOf(vmInfo.getVmPid()));
-        processSection.add(entry);
-        long startTime = vmInfo.getStartTimeStamp();
-        DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.FULL);
-        entry = new TableEntry(_("VM_INFO_START_TIME"), df.format(new Date(startTime)));
+        entry = new TableEntry(_("VM_INFO_PROCESS_ID"), facade.getVmPid());
         processSection.add(entry);
-        long stopTime = vmInfo.getStopTimeStamp();
-        if (stopTime >= startTime) {
-            // Only show a stop time if we have actually stopped.
-            entry = new TableEntry(_("VM_INFO_STOP_TIME"), df.format(new Date(stopTime)));
-        } else {
-            entry = new TableEntry(_("VM_INFO_STOP_TIME"), _("VM_INFO_RUNNING"));
-        }
+        entry = new TableEntry(_("VM_INFO_START_TIME"), facade.getStartTimeStamp());
+        processSection.add(entry);
+        entry = new TableEntry(_("VM_INFO_STOP_TIME"), facade.getStopTimeStamp());
         processSection.add(entry);
 
         Section javaSection = new Section(_("VM_INFO_SECTION_JAVA"));
         allSections.add(javaSection);
 
-        entry = new TableEntry(_("VM_INFO_MAIN_CLASS"), vmInfo.getMainClass());
+        entry = new TableEntry(_("VM_INFO_MAIN_CLASS"), facade.getMainClass());
         javaSection.add(entry);
-        entry = new TableEntry(_("VM_INFO_COMMAND_LINE"), vmInfo.getJavaCommandLine());
+        entry = new TableEntry(_("VM_INFO_COMMAND_LINE"), facade.getJavaCommandLine());
         javaSection.add(entry);
-        entry = new TableEntry(_("VM_INFO_JAVA_VERSION"), vmInfo.getJavaVersion());
+        entry = new TableEntry(_("VM_INFO_JAVA_VERSION"), facade.getJavaVersion());
         javaSection.add(entry);
-        entry = new TableEntry(_("VM_INFO_VM"), _("VM_INFO_VM_NAME_AND_VERSION", vmInfo.getVmName(), vmInfo.getVmVersion()));
+        entry = new TableEntry(_("VM_INFO_VM"), facade.getVmNameAndVersion());
         javaSection.add(entry);
 
-        JPanel table = SimpleTable.createTable(allSections);
+        SimpleTable simpleTable = new SimpleTable();
+        JPanel table = simpleTable.createTable(allSections);
         table.setBorder(Components.smallBorder());
         panel.add(table, BorderLayout.PAGE_START);