Mercurial > hg > release > thermostat-0.9
changeset 54:c2fa392782bd
update the agent/vm tree asynchronously
author | Omair Majid <omajid@redhat.com> |
---|---|
date | Wed, 25 Jan 2012 12:18:00 -0500 |
parents | fceb773a3938 |
children | fc0ff5ca8e76 |
files | src/com/redhat/thermostat/client/DummyFacade.java src/com/redhat/thermostat/client/HostPanelFacade.java src/com/redhat/thermostat/client/HostRef.java src/com/redhat/thermostat/client/MainWindowFacade.java src/com/redhat/thermostat/client/MainWindowFacadeImpl.java src/com/redhat/thermostat/client/Ref.java src/com/redhat/thermostat/client/SummaryPanelFacade.java src/com/redhat/thermostat/client/VmRef.java src/com/redhat/thermostat/client/ui/MainWindow.java src/com/redhat/thermostat/common/utils/StringUtils.java |
diffstat | 10 files changed, 347 insertions(+), 97 deletions(-) [+] |
line wrap: on
line diff
--- a/src/com/redhat/thermostat/client/DummyFacade.java Wed Jan 25 11:49:32 2012 -0500 +++ b/src/com/redhat/thermostat/client/DummyFacade.java Wed Jan 25 12:18:00 2012 -0500 @@ -45,6 +45,10 @@ 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; @@ -60,6 +64,7 @@ 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())); @@ -86,6 +91,16 @@ } @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>(); } @@ -293,4 +308,14 @@ return stat; } + @Override + public void start() { + // no-op + } + + @Override + public void stop() { + // no-op + } + }
--- a/src/com/redhat/thermostat/client/HostPanelFacade.java Wed Jan 25 11:49:32 2012 -0500 +++ b/src/com/redhat/thermostat/client/HostPanelFacade.java Wed Jan 25 12:18:00 2012 -0500 @@ -40,18 +40,18 @@ import com.redhat.thermostat.common.NetworkInfo; public interface HostPanelFacade { - public abstract HostInfo getHostInfo(); + public HostInfo getHostInfo(); - public abstract NetworkInfo getNetworkInfo(); + public NetworkInfo getNetworkInfo(); - public abstract DiscreteTimeData<Double>[] getCpuLoad(); + public DiscreteTimeData<Double>[] getCpuLoad(); - public abstract DiscreteTimeData<Long>[] getMemoryUsage(MemoryType type); + public DiscreteTimeData<Long>[] getMemoryUsage(MemoryType type); - public abstract MemoryType[] getMemoryTypesToDisplay(); + public MemoryType[] getMemoryTypesToDisplay(); - public abstract boolean isMemoryTypeDisplayed(MemoryType type); + public boolean isMemoryTypeDisplayed(MemoryType type); - public abstract void setDisplayMemoryType(MemoryType type, boolean selected); + public void setDisplayMemoryType(MemoryType type, boolean selected); }
--- a/src/com/redhat/thermostat/client/HostRef.java Wed Jan 25 11:49:32 2012 -0500 +++ b/src/com/redhat/thermostat/client/HostRef.java Wed Jan 25 12:18:00 2012 -0500 @@ -36,7 +36,7 @@ package com.redhat.thermostat.client; -public class HostRef { +public class HostRef implements Ref { private final String uid; private final String name; @@ -59,6 +59,34 @@ return name; } + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (obj == this) { + return true; + } + if (obj.getClass() != this.getClass()) { + return false; + } + HostRef other = (HostRef) obj; + if (equals(this.uid, other.uid) && equals(this.name, other.name)) { + return true; + } + return false; + } + + private static boolean equals(Object obj1, Object obj2) { + return (obj1 == null && obj2 == null) || (obj1 != null && obj1.equals(obj2)); + } + + @Override + public int hashCode() { + return uid.hashCode(); + } + + @Override public boolean matches(String filter) { return getHostName().contains(filter) || getAgentId().contains(filter); }
--- a/src/com/redhat/thermostat/client/MainWindowFacade.java Wed Jan 25 11:49:32 2012 -0500 +++ b/src/com/redhat/thermostat/client/MainWindowFacade.java Wed Jan 25 12:18:00 2012 -0500 @@ -36,10 +36,20 @@ package com.redhat.thermostat.client; +import javax.swing.tree.TreeModel; + public interface MainWindowFacade { - public abstract HostRef[] getHosts(); + public void start(); + + public void stop(); + + public HostRef[] getHosts(); - public abstract VmRef[] getVms(HostRef ref); + public VmRef[] getVms(HostRef ref); + + public TreeModel getHostVmTree(); + + public void setHostVmTreeFilter(String filter); }
--- a/src/com/redhat/thermostat/client/MainWindowFacadeImpl.java Wed Jan 25 11:49:32 2012 -0500 +++ b/src/com/redhat/thermostat/client/MainWindowFacadeImpl.java Wed Jan 25 12:18:00 2012 -0500 @@ -36,32 +36,73 @@ package com.redhat.thermostat.client; +import static com.redhat.thermostat.client.Translate._; + +import java.io.PrintStream; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; +import javax.swing.SwingWorker; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreeNode; + 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.utils.LoggingUtils; +import com.redhat.thermostat.common.utils.StringUtils; public class MainWindowFacadeImpl implements MainWindowFacade { private static final Logger logger = LoggingUtils.getLogger(MainWindowFacadeImpl.class); + 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; + 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 + public void stop() { + backgroundUpdater.cancel(); } @Override @@ -99,5 +140,137 @@ return vmRefs.toArray(new VmRef[0]); } + @Override + public TreeModel getHostVmTree() { + return publishedTreeModel; + } + + private Ref[] getChildren(Ref parent) { + if (parent == null) { + return getHosts(); + } else if (parent instanceof HostRef) { + HostRef host = (HostRef) parent; + return getVms(host); + } + return new Ref[0]; + } + + @Override + public void setHostVmTreeFilter(String filter) { + this.filterText = filter; + doUpdateTreeAsync(); + } + + public void doUpdateTreeAsync() { + BackgroundTreeModelWorker worker = new BackgroundTreeModelWorker(this, publishedTreeModel, publishedRoot); + worker.execute(); + } + + /** + * Updates a TreeModel in the background in an Swing EDT-safe manner. + */ + private static class BackgroundTreeModelWorker extends SwingWorker<DefaultMutableTreeNode, Void> { + + private final DefaultTreeModel treeModel; + private MainWindowFacadeImpl facade; + private DefaultMutableTreeNode treeRoot; + + public BackgroundTreeModelWorker(MainWindowFacadeImpl facade, DefaultTreeModel model, DefaultMutableTreeNode root) { + this.facade = facade; + this.treeModel = model; + this.treeRoot = root; + } + + @Override + protected DefaultMutableTreeNode doInBackground() throws Exception { + DefaultMutableTreeNode root = new DefaultMutableTreeNode(); + List<HostRef> hostsInRemoteModel = Arrays.asList(facade.getHosts()); + buildSubTree(root, hostsInRemoteModel, facade.filterText); + return root; + } + + private boolean buildSubTree(DefaultMutableTreeNode parent, List<? extends Ref> objectsInRemoteModel, String filter) { + boolean subTreeMatches = false; + for (Ref inRemoteModel : objectsInRemoteModel) { + DefaultMutableTreeNode inTreeNode = new DefaultMutableTreeNode(inRemoteModel); + + boolean shouldInsert = false; + if (filter == null || inRemoteModel.matches(filter)) { + shouldInsert = true; + } + + List<Ref> children = Arrays.asList(facade.getChildren(inRemoteModel)); + boolean subtreeResult = buildSubTree(inTreeNode, children, filter); + if (subtreeResult) { + shouldInsert = true; + } + + if (shouldInsert) { + parent.add(inTreeNode); + subTreeMatches = true; + } + } + return subTreeMatches; + } + + @Override + protected void done() { + DefaultMutableTreeNode sourceRoot; + try { + sourceRoot = get(); + syncTree(sourceRoot, treeModel, treeRoot); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + } + + private void syncTree(DefaultMutableTreeNode sourceRoot, DefaultTreeModel targetModel, DefaultMutableTreeNode targetNode) { + List<DefaultMutableTreeNode> sourceChildren = Collections.list(sourceRoot.children()); + List<DefaultMutableTreeNode> targetChildren = Collections.list(targetNode.children()); + for (DefaultMutableTreeNode sourceChild : sourceChildren) { + Ref sourceRef = (Ref) sourceChild.getUserObject(); + DefaultMutableTreeNode targetChild = null; + for (DefaultMutableTreeNode aChild : targetChildren) { + Ref targetRef = (Ref) aChild.getUserObject(); + if (targetRef.equals(sourceRef)) { + targetChild = aChild; + break; + } + } + + if (targetChild == null) { + targetChild = new DefaultMutableTreeNode(sourceRef); + targetModel.insertNodeInto(targetChild, targetNode, targetNode.getChildCount()); + } + + syncTree(sourceChild, targetModel, targetChild); + } + + for (DefaultMutableTreeNode targetChild : targetChildren) { + Ref targetRef = (Ref) targetChild.getUserObject(); + boolean matchFound = false; + for (DefaultMutableTreeNode sourceChild : sourceChildren) { + Ref sourceRef = (Ref) sourceChild.getUserObject(); + if (targetRef.equals(sourceRef)) { + matchFound = true; + break; + } + } + + if (!matchFound) { + targetModel.removeNodeFromParent(targetChild); + } + } + } + } + + private static void printTree(PrintStream out, TreeNode node, int depth) { + out.println(StringUtils.repeat(" ", depth) + node.toString()); + for (TreeNode child : (List<TreeNode>) Collections.list(node.children())) { + printTree(out, child, depth + 1); + } + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/redhat/thermostat/client/Ref.java Wed Jan 25 12:18:00 2012 -0500 @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not 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 Ref { + + public boolean matches(String filter); + +}
--- a/src/com/redhat/thermostat/client/SummaryPanelFacade.java Wed Jan 25 11:49:32 2012 -0500 +++ b/src/com/redhat/thermostat/client/SummaryPanelFacade.java Wed Jan 25 12:18:00 2012 -0500 @@ -40,9 +40,9 @@ public interface SummaryPanelFacade { - public abstract long getTotalConnectedVms(); + public long getTotalConnectedVms(); - public abstract long getTotalConnectedAgents(); + public long getTotalConnectedAgents(); public List<String> getIssues();
--- a/src/com/redhat/thermostat/client/VmRef.java Wed Jan 25 11:49:32 2012 -0500 +++ b/src/com/redhat/thermostat/client/VmRef.java Wed Jan 25 12:18:00 2012 -0500 @@ -36,7 +36,7 @@ package com.redhat.thermostat.client; -public class VmRef { +public class VmRef implements Ref { private final HostRef hostRef; private final String uid; @@ -65,6 +65,34 @@ return name; } + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (obj == this) { + return true; + } + if (obj.getClass() != this.getClass()) { + return false; + } + VmRef other = (VmRef) obj; + if (equals(this.hostRef, other.hostRef) && equals(this.uid, other.uid) && equals(this.name, other.name)) { + return true; + } + return false; + } + + private static boolean equals(Object obj1, Object obj2) { + return (obj1 == null && obj2 == null) || (obj1 != null && obj1.equals(obj2)); + } + + @Override + public int hashCode() { + return uid.hashCode(); + } + + @Override public boolean matches(String filter) { return getName().contains(filter) || getId().contains(filter); }
--- a/src/com/redhat/thermostat/client/ui/MainWindow.java Wed Jan 25 11:49:32 2012 -0500 +++ b/src/com/redhat/thermostat/client/ui/MainWindow.java Wed Jan 25 12:18:00 2012 -0500 @@ -47,8 +47,6 @@ import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; -import java.util.ArrayList; -import java.util.List; import javax.swing.BorderFactory; import javax.swing.JFrame; @@ -63,7 +61,6 @@ import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.KeyStroke; -import javax.swing.ScrollPaneConstants; import javax.swing.ToolTipManager; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; @@ -73,14 +70,11 @@ import javax.swing.text.Document; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellRenderer; -import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeModel; -import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import com.redhat.thermostat.client.ApplicationInfo; -import com.redhat.thermostat.client.ClientArgs; import com.redhat.thermostat.client.HostRef; import com.redhat.thermostat.client.MainWindowFacade; import com.redhat.thermostat.client.UiFacadeFactory; @@ -90,15 +84,13 @@ private static final long serialVersionUID = 5608972421496808177L; - private final DefaultMutableTreeNode root = new DefaultMutableTreeNode(_("MAIN_WINDOW_TREE_ROOT_NAME")); - private final DefaultTreeModel treeModel = new DefaultTreeModel(root); - private final UiFacadeFactory facadeFactory; private final MainWindowFacade facade; private JPanel contentArea = null; + + private JTextField searchField = null; private JTree agentVmTree = null; - private JTextField searchField = null; public MainWindow(UiFacadeFactory facadeFactory) { super(); @@ -106,9 +98,10 @@ this.facadeFactory = facadeFactory; this.facade = facadeFactory.getMainWindow(); - searchField = new JTextField(); - agentVmTree = new AgentVmTree(treeModel); + TreeModel model = facade.getHostVmTree(); + agentVmTree = new JTree(model); + agentVmTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); agentVmTree.setCellRenderer(new AgentVmTreeCellRenderer()); ToolTipManager.sharedInstance().registerComponent(agentVmTree); contentArea = new JPanel(new BorderLayout()); @@ -116,11 +109,11 @@ setupMenus(); setupPanels(); - agentVmTree.setSelectionPath(new TreePath(root.getPath())); - - buildTree(""); + agentVmTree.setSelectionPath(new TreePath(((DefaultMutableTreeNode) model.getRoot()).getPath())); setDefaultCloseOperation(DISPOSE_ON_CLOSE); + + this.facade.start(); } private void setupMenus() { @@ -151,7 +144,7 @@ JMenuItem fileExitMenu = new JMenuItem(_("MENU_FILE_EXIT")); fileExitMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, InputEvent.CTRL_DOWN_MASK)); - fileExitMenu.addActionListener(new ShtudownClient(this)); + fileExitMenu.addActionListener(new ShutdownClient(this.facade, this)); fileMenu.add(fileExitMenu); JMenu helpMenu = new JMenu(_("MENU_HELP")); @@ -203,10 +196,13 @@ String filter = null; try { filter = doc.getText(0, doc.getLength()); + if (filter.trim().equals("")) { + filter = null; + } } catch (BadLocationException ble) { // ignore } - buildTree(filter); + facade.setHostVmTreeFilter(filter); } }); @@ -236,7 +232,6 @@ contentArea.revalidate(); } } - }); JScrollPane treeScrollPane = new JScrollPane(agentVmTree); @@ -257,81 +252,20 @@ return result; } - private void buildTree(String filter) { - root.removeAllChildren(); - treeModel.setRoot(null); - // paths to expand. only expand paths when a vm matches (to ensure it is - // visible) - - List<TreeNode[]> pathsToExpand = new ArrayList<TreeNode[]>(); - if (filter == null || filter.trim().equals("")) { - DefaultMutableTreeNode agentNode; - HostRef[] agentRefs = facade.getHosts(); - for (HostRef hostRef : agentRefs) { - agentNode = new DefaultMutableTreeNode(hostRef); - root.add(agentNode); - VmRef[] vmRefs = facade.getVms(hostRef); - for (VmRef vmRef : vmRefs) { - agentNode.add(new DefaultMutableTreeNode(vmRef)); - } - } - treeModel.setRoot(root); - } else { - DefaultMutableTreeNode agentNode; - for (HostRef hostRef : facade.getHosts()) { - if (hostRef.matches(filter)) { - agentNode = new DefaultMutableTreeNode(hostRef); - root.add(agentNode); - VmRef[] vmRefs = facade.getVms(hostRef); - for (VmRef vmRef : vmRefs) { - agentNode.add(new DefaultMutableTreeNode(vmRef)); - } - } else { - agentNode = null; - for (VmRef vmRef : facade.getVms(hostRef)) { - if (vmRef.matches(filter)) { - if (agentNode == null) { - agentNode = new DefaultMutableTreeNode(hostRef); - root.add(agentNode); - } - DefaultMutableTreeNode vmNode = new DefaultMutableTreeNode(vmRef); - agentNode.add(vmNode); - pathsToExpand.add(vmNode.getPath()); - } - } - } - } - if (root.getChildCount() > 0) { - treeModel.setRoot(root); - } - - } - for (TreeNode[] path : pathsToExpand) { - agentVmTree.expandPath(new TreePath(path).getParentPath()); - } - agentVmTree.expandRow(0); - } - - public static class ShtudownClient implements ActionListener { + public static class ShutdownClient implements ActionListener { private JFrame toDispose; + private MainWindowFacade facade; - public ShtudownClient(JFrame toDispose) { + public ShutdownClient(MainWindowFacade facade, JFrame toDispose) { + this.facade = facade; this.toDispose = toDispose; } @Override public void actionPerformed(ActionEvent e) { toDispose.dispose(); - } - } - - private static class AgentVmTree extends JTree { - private static final long serialVersionUID = 8894141735861100579L; - - public AgentVmTree(TreeModel model) { - super(model); - getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + facade.stop(); } }
--- a/src/com/redhat/thermostat/common/utils/StringUtils.java Wed Jan 25 11:49:32 2012 -0500 +++ b/src/com/redhat/thermostat/common/utils/StringUtils.java Wed Jan 25 12:18:00 2012 -0500 @@ -57,4 +57,13 @@ public static String quote(String toQuote) { return new String("\"" + toQuote + "\""); } + + public static String repeat(String text, int times) { + StringBuilder builder = new StringBuilder(text.length() * times); + for (int i = 0; i < times; i++) { + builder.append(text); + } + return builder.toString(); + } + }