Mercurial > hg > release > thermostat-1.0
changeset 362:00ffcc68584f
Add VMTree label annotations and some tests.
review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-June/001771.html
reviewed-by: omajid
PR 1002
line wrap: on
line diff
--- a/client/core/src/main/java/com/redhat/thermostat/client/MainView.java Tue Jun 12 11:30:24 2012 +0200 +++ b/client/core/src/main/java/com/redhat/thermostat/client/MainView.java Tue Jun 12 11:30:24 2012 +0200 @@ -41,6 +41,7 @@ import java.util.List; import com.redhat.thermostat.client.osgi.service.MenuAction; +import com.redhat.thermostat.client.osgi.service.ReferenceDecorator; import com.redhat.thermostat.client.osgi.service.VMContextAction; import com.redhat.thermostat.client.osgi.service.Filter; import com.redhat.thermostat.common.ActionListener; @@ -64,7 +65,7 @@ void addActionListener(ActionListener<Action> capture); - void updateTree(List<Filter> filter, HostsVMsLoader any); + void updateTree(List<Filter> filter, List<ReferenceDecorator> decorators, HostsVMsLoader any); String getHostVmTreeFilterText(); void setWindowTitle(String title);
--- a/client/core/src/main/java/com/redhat/thermostat/client/MainWindowControllerImpl.java Tue Jun 12 11:30:24 2012 +0200 +++ b/client/core/src/main/java/com/redhat/thermostat/client/MainWindowControllerImpl.java Tue Jun 12 11:30:24 2012 +0200 @@ -51,6 +51,7 @@ import com.redhat.thermostat.client.MainView.Action; import com.redhat.thermostat.client.osgi.service.Filter; import com.redhat.thermostat.client.osgi.service.MenuAction; +import com.redhat.thermostat.client.osgi.service.ReferenceDecorator; import com.redhat.thermostat.client.osgi.service.VMContextAction; import com.redhat.thermostat.client.ui.AboutDialog; import com.redhat.thermostat.client.ui.AgentConfigurationController; @@ -79,7 +80,9 @@ private static final Logger logger = LoggingUtils.getLogger(MainWindowControllerImpl.class); - private List<Filter> filters; + private List<Filter> vmTreefilters; + private List<ReferenceDecorator> vmTreeDecorators; + private Timer backgroundUpdater; private MainView view; @@ -106,28 +109,85 @@ } }; - private VMTreeFilterRegistry filterRegistry; + // FIXME: sort out the code duplication in the registry listeners private TreeViewFilter treeFilter; + private VMTreeFilterRegistry filterRegistry; + private ActionListener<ThermostatExtensionRegistry.Action> filterListener = + new ActionListener<ThermostatExtensionRegistry.Action>() + { + @Override + public void actionPerformed(ActionEvent<com.redhat.thermostat.client.ThermostatExtensionRegistry.Action> + actionEvent) + { + Filter filter = (Filter) actionEvent.getPayload(); + + switch (actionEvent.getActionId()) { + case SERVICE_ADDED: + vmTreefilters.add(filter); + doUpdateTreeAsync(); + break; + + case SERVICE_REMOVED: + vmTreefilters.remove(filter); + doUpdateTreeAsync(); + break; + + default: + logger.log(Level.WARNING, "received unknown event from VMTreeFilterRegistry: " + + actionEvent.getActionId()); + break; + } + } + }; + + private VMTreeDecoratorRegistry decoratorRegistry; + private ActionListener<ThermostatExtensionRegistry.Action> decoratorListener = + new ActionListener<ThermostatExtensionRegistry.Action> () + { + public void actionPerformed(com.redhat.thermostat.common.ActionEvent<ThermostatExtensionRegistry.Action> + actionEvent) + { + ReferenceDecorator decorator = (ReferenceDecorator) actionEvent.getPayload(); + switch (actionEvent.getActionId()) { + case SERVICE_ADDED: + vmTreeDecorators.add(decorator); + doUpdateTreeAsync(); + break; + + case SERVICE_REMOVED: + vmTreeDecorators.remove(decorator); + doUpdateTreeAsync(); + break; + + default: + logger.log(Level.WARNING, "received unknown event from ReferenceDecorator: " + + actionEvent.getActionId()); + break; + } + }; + }; private boolean showHistory; private VmInformationControllerProvider vmInfoControllerProvider; - public MainWindowControllerImpl(UiFacadeFactory facadeFactory, MainView view, - BundleContext context) + public MainWindowControllerImpl(UiFacadeFactory facadeFactory, MainView view, RegistryFactory registryFactory) { try { - filterRegistry = new VMTreeFilterRegistry(context); - menuRegistry = new MenuRegistry(context); + filterRegistry = registryFactory.createVMTreeFilterRegistry(); + decoratorRegistry = registryFactory.createVMTreeDecoratorRegistry(); + menuRegistry = registryFactory.createMenuRegistry(); } catch (InvalidSyntaxException e) { throw new RuntimeException(e); } - this.filters = new CopyOnWriteArrayList<>(); + vmTreeDecorators = new CopyOnWriteArrayList<>(); + + vmTreefilters = new CopyOnWriteArrayList<>(); treeFilter = new TreeViewFilter(); - filters.add(treeFilter); + vmTreefilters.add(treeFilter); this.facadeFactory = facadeFactory; @@ -149,32 +209,11 @@ menuRegistry.addMenuListener(menuListener); menuRegistry.start(); - filterRegistry.addActionListener(new ActionListener<ThermostatExtensionRegistry.Action>() { - @Override - public void actionPerformed(ActionEvent<com.redhat.thermostat.client.ThermostatExtensionRegistry.Action> - actionEvent) - { - Filter filter = (Filter) actionEvent.getPayload(); - - switch (actionEvent.getActionId()) { - case SERVICE_ADDED: - filters.add(filter); - doUpdateTreeAsync(); - break; - - case SERVICE_REMOVED: - filters.remove(filter); - doUpdateTreeAsync(); - break; - - default: - logger.log(Level.WARNING, "received unknown event from VMTreeFilterRegistry: " + - actionEvent.getActionId()); - break; - } - } - }); + filterRegistry.addActionListener(filterListener); filterRegistry.start(); + + decoratorRegistry.addActionListener(decoratorListener); + decoratorRegistry.start(); } private class HostsVMsLoaderImpl implements HostsVMsLoader { @@ -204,6 +243,13 @@ /** * This method is for testing purpouse only + */ + List<ReferenceDecorator> getVmTreeDecorators() { + return vmTreeDecorators; + } + + /** + * This method is for testing purpouse only */ MenuRegistry.MenuListener getMenuListener() { return menuListener; @@ -256,7 +302,7 @@ public void doUpdateTreeAsync() { HostsVMsLoader loader = new HostsVMsLoaderImpl(); - view.updateTree(filters, loader); + view.updateTree(vmTreefilters, vmTreeDecorators, loader); } private void initView(MainView mainView) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/core/src/main/java/com/redhat/thermostat/client/RegistryFactory.java Tue Jun 12 11:30:24 2012 +0200 @@ -0,0 +1,60 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.client; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.InvalidSyntaxException; + +class RegistryFactory { + + private BundleContext context; + RegistryFactory(BundleContext context) { + this.context = context; + } + + VMTreeDecoratorRegistry createVMTreeDecoratorRegistry() throws InvalidSyntaxException { + return new VMTreeDecoratorRegistry(context); + } + + VMTreeFilterRegistry createVMTreeFilterRegistry() throws InvalidSyntaxException { + return new VMTreeFilterRegistry(context); + } + + MenuRegistry createMenuRegistry() throws InvalidSyntaxException { + return new MenuRegistry(context); + } +}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ThermostatExtensionRegistry.java Tue Jun 12 11:30:24 2012 +0200 +++ b/client/core/src/main/java/com/redhat/thermostat/client/ThermostatExtensionRegistry.java Tue Jun 12 11:30:24 2012 +0200 @@ -54,11 +54,11 @@ private ActionNotifier<Action> actionNotifier = new ActionNotifier<>(this); - private ServiceTracker filterTracker; + private ServiceTracker tracker; public ThermostatExtensionRegistry(BundleContext context, String filter, final Class<E> classType) throws InvalidSyntaxException { - filterTracker = new ServiceTracker(context, FrameworkUtil.createFilter(filter), null) { + tracker = new ServiceTracker(context, FrameworkUtil.createFilter(filter), null) { @Override public Object addingService(ServiceReference reference) { @@ -82,11 +82,11 @@ } public void start() { - filterTracker.open(); + tracker.open(); } public void stop() { - filterTracker.close(); + tracker.close(); } public void addActionListener(ActionListener<Action> l) {
--- a/client/core/src/main/java/com/redhat/thermostat/client/UiFacadeFactoryImpl.java Tue Jun 12 11:30:24 2012 +0200 +++ b/client/core/src/main/java/com/redhat/thermostat/client/UiFacadeFactoryImpl.java Tue Jun 12 11:30:24 2012 +0200 @@ -67,7 +67,8 @@ @Override public MainWindowController getMainWindow() { MainView mainView = new MainWindow(); - return new MainWindowControllerImpl(this, mainView, context); + RegistryFactory registryFactory = new RegistryFactory(context); + return new MainWindowControllerImpl(this, mainView, registryFactory); } @Override
--- a/client/core/src/main/java/com/redhat/thermostat/client/VMTreeDecoratorRegistry.java Tue Jun 12 11:30:24 2012 +0200 +++ b/client/core/src/main/java/com/redhat/thermostat/client/VMTreeDecoratorRegistry.java Tue Jun 12 11:30:24 2012 +0200 @@ -36,6 +36,17 @@ package com.redhat.thermostat.client; -public class VMTreeDecoratorRegistry { +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.InvalidSyntaxException; + +import com.redhat.thermostat.client.osgi.service.ReferenceDecorator; +class VMTreeDecoratorRegistry extends ThermostatExtensionRegistry<ReferenceDecorator> { + + private static final String FILTER = "(&(" + Constants.OBJECTCLASS + "=" + ReferenceDecorator.class.getName() + "))"; + + public VMTreeDecoratorRegistry(BundleContext context) throws InvalidSyntaxException { + super(context, FILTER, ReferenceDecorator.class); + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/core/src/main/java/com/redhat/thermostat/client/osgi/service/ReferenceDecorator.java Tue Jun 12 11:30:24 2012 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.client.osgi.service; + +import com.redhat.thermostat.client.ui.Decorator; + +/** + * This interface allows plugins to install a custom {@link Decorator} into + * the Reference List view. + * + * <br /><br /> + * + * Active {@link ReferenceDecorator}s are first queried against their filters + * and then installed into the view if the filter passes. + */ +public interface ReferenceDecorator { + + Decorator getDecorator(); + Filter getFilter(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/DecoratedDefaultMutableTreeNode.java Tue Jun 12 11:30:24 2012 +0200 @@ -0,0 +1,67 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.client.ui; + +import java.util.ArrayList; +import java.util.List; + +import javax.swing.tree.DefaultMutableTreeNode; + +import com.redhat.thermostat.client.osgi.service.ReferenceDecorator; +import com.redhat.thermostat.common.dao.Ref; + +class DecoratedDefaultMutableTreeNode extends DefaultMutableTreeNode { + + private List<ReferenceDecorator> decorators; + + DecoratedDefaultMutableTreeNode(Ref ref) { + super(ref); + decorators = new ArrayList<>(); + } + + public void addDecorator(ReferenceDecorator decorator) { + decorators.add(decorator); + } + + public void setDecorators(List<ReferenceDecorator> decorators) { + this.decorators = decorators; + } + + public List<ReferenceDecorator> getDecorators() { + return decorators; + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/Decorator.java Tue Jun 12 11:30:24 2012 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not 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; + + +/** + * A {@link Decorator} allows plugins to install special visual clues on + * selected components. + * + * <br /><br /> + * + * A {@link Decorator} itself is not an entry point. + */ +public interface Decorator { + + public static enum Quadrant { + TOP_LEFT, + BOTTOM_LEFT, + MAIN + } + + String getLabel(String originalLabel); + IconResource getIconResource(); +}
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/MainWindow.java Tue Jun 12 11:30:24 2012 +0200 +++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/MainWindow.java Tue Jun 12 11:30:24 2012 +0200 @@ -98,6 +98,7 @@ import com.redhat.thermostat.client.MainView; import com.redhat.thermostat.client.locale.LocaleResources; import com.redhat.thermostat.client.osgi.service.MenuAction; +import com.redhat.thermostat.client.osgi.service.ReferenceDecorator; import com.redhat.thermostat.client.osgi.service.VMContextAction; import com.redhat.thermostat.client.osgi.service.Filter; import com.redhat.thermostat.common.ActionListener; @@ -116,21 +117,27 @@ private final DefaultTreeModel treeModel; private DefaultMutableTreeNode treeRoot; + private List<Filter> filters; + private List<ReferenceDecorator> decorators; + private HostsVMsLoader hostsVMsLoader; public BackgroundTreeModelWorker(DefaultTreeModel model, DefaultMutableTreeNode root, - List<Filter> filters, HostsVMsLoader hostsVMsLoader) + List<Filter> filters, List<ReferenceDecorator> decorators, + HostsVMsLoader hostsVMsLoader) { this.filters = filters; this.treeModel = model; this.treeRoot = root; this.hostsVMsLoader = hostsVMsLoader; + this.decorators = decorators; } @Override protected DefaultMutableTreeNode doInBackground() throws Exception { DefaultMutableTreeNode root = new DefaultMutableTreeNode(); + Collection<HostRef> hostsInRemoteModel = hostsVMsLoader.getHosts(); buildSubTree(root, hostsInRemoteModel); return root; @@ -139,7 +146,8 @@ private boolean buildSubTree(DefaultMutableTreeNode parent, Collection<? extends Ref> objectsInRemoteModel) { boolean subTreeMatches = false; for (Ref inRemoteModel : objectsInRemoteModel) { - DefaultMutableTreeNode inTreeNode = new DefaultMutableTreeNode(inRemoteModel); + DecoratedDefaultMutableTreeNode inTreeNode = + new DecoratedDefaultMutableTreeNode(inRemoteModel); boolean shouldInsert = false; if (filters == null) { @@ -153,7 +161,7 @@ } } } - + Collection<? extends Ref> children = getChildren(inRemoteModel); boolean subtreeResult = buildSubTree(inTreeNode, children); if (subtreeResult) { @@ -161,6 +169,13 @@ } if (shouldInsert) { + for (ReferenceDecorator decorator : decorators) { + Filter filter = decorator.getFilter(); + if (filter != null && filter.matches(inRemoteModel)) { + inTreeNode.addDecorator(decorator); + } + } + parent.add(inTreeNode); subTreeMatches = true; } @@ -192,9 +207,11 @@ } private void syncTree(DefaultMutableTreeNode sourceRoot, DefaultTreeModel targetModel, DefaultMutableTreeNode targetNode) { + @SuppressWarnings("unchecked") // We know what we put into these trees. List<DefaultMutableTreeNode> sourceChildren = Collections.list(sourceRoot.children()); @SuppressWarnings("unchecked") + List<DefaultMutableTreeNode> targetChildren = Collections.list(targetNode.children()); for (DefaultMutableTreeNode sourceChild : sourceChildren) { Ref sourceRef = (Ref) sourceChild.getUserObject(); @@ -208,7 +225,11 @@ } if (targetChild == null) { - targetChild = new DefaultMutableTreeNode(sourceRef); + targetChild = new DecoratedDefaultMutableTreeNode(sourceRef); + if (sourceChild instanceof DecoratedDefaultMutableTreeNode) { + DecoratedDefaultMutableTreeNode source = (DecoratedDefaultMutableTreeNode) sourceChild; + ((DecoratedDefaultMutableTreeNode) targetChild).setDecorators(source.getDecorators()); + } targetModel.insertNodeInto(targetChild, targetNode, targetNode.getChildCount()); } @@ -533,8 +554,27 @@ @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { - setToolTipText(createToolTipText(((DefaultMutableTreeNode) value).getUserObject())); - return super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); + + Object node = ((DefaultMutableTreeNode) value).getUserObject(); + setToolTipText(createToolTipText(node)); + + Component component = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); + if (value instanceof DecoratedDefaultMutableTreeNode) { + DecoratedDefaultMutableTreeNode treeNode = (DecoratedDefaultMutableTreeNode) value; + setAnnotation(treeNode, node, component); + } + + return component; + } + + private void setAnnotation(DecoratedDefaultMutableTreeNode treeNode, Object value, Component component) { + + List<ReferenceDecorator> decorators = treeNode.getDecorators(); + for (ReferenceDecorator decorator : decorators) { + String newText = decorator.getDecorator().getLabel(getText()); + setText(newText); + setLabelFor(component); + } } private String createToolTipText(Object value) { @@ -562,20 +602,6 @@ } } - private static class Separator extends JPopupMenu.Separator { - - private static final long serialVersionUID = 3061771592573345826L; - - @Override - public Dimension getPreferredSize() { - Dimension result = super.getPreferredSize(); - if (result.height < 1) { - result.height = 5; - } - return result; - } - } - @Override public void addActionListener(ActionListener<Action> l) { actionNotifier.addActionListener(l); @@ -594,8 +620,10 @@ } @Override - public void updateTree(List<Filter> filters, HostsVMsLoader hostsVMsLoader) { - BackgroundTreeModelWorker worker = new BackgroundTreeModelWorker(publishedTreeModel, publishedRoot, filters, hostsVMsLoader); + public void updateTree(List<Filter> filters, List<ReferenceDecorator> decorators, HostsVMsLoader hostsVMsLoader) { + BackgroundTreeModelWorker worker = + new BackgroundTreeModelWorker(publishedTreeModel, publishedRoot, + filters, decorators, hostsVMsLoader); worker.execute(); }
--- a/client/core/src/test/java/com/redhat/thermostat/client/MainWindowControllerImplTest.java Tue Jun 12 11:30:24 2012 +0200 +++ b/client/core/src/test/java/com/redhat/thermostat/client/MainWindowControllerImplTest.java Tue Jun 12 11:30:24 2012 +0200 @@ -64,9 +64,11 @@ import org.mockito.ArgumentCaptor; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; +import org.osgi.util.tracker.ServiceTracker; import com.redhat.thermostat.client.osgi.service.Filter; import com.redhat.thermostat.client.osgi.service.MenuAction; +import com.redhat.thermostat.client.osgi.service.ReferenceDecorator; import com.redhat.thermostat.client.osgi.service.VMContextAction; import com.redhat.thermostat.client.ui.SummaryController; import com.redhat.thermostat.client.ui.SummaryView; @@ -105,6 +107,13 @@ private VMContextAction action1; private VMContextAction action2; + private VMTreeFilterRegistry filters; + private VMTreeDecoratorRegistry decorators; + private MenuRegistry menues; + + private ActionListener<ThermostatExtensionRegistry.Action> filtersListener; + private ActionListener<ThermostatExtensionRegistry.Action> decoratorsListener; + @BeforeClass public static void setUpOnce() { // TODO remove when controller uses mocked objects rather than real swing objects @@ -133,9 +142,22 @@ view = mock(MainView.class); ArgumentCaptor<ActionListener> grabListener = ArgumentCaptor.forClass(ActionListener.class); doNothing().when(view).addActionListener(grabListener.capture()); + + RegistryFactory registryFactory = mock(RegistryFactory.class); + filters = mock(VMTreeFilterRegistry.class); + decorators = mock(VMTreeDecoratorRegistry.class); + menues = mock(MenuRegistry.class); - BundleContext registry = mock(BundleContext.class); + when(registryFactory.createMenuRegistry()).thenReturn(menues); + when(registryFactory.createVMTreeDecoratorRegistry()).thenReturn(decorators); + when(registryFactory.createVMTreeFilterRegistry()).thenReturn(filters); + + ArgumentCaptor<ActionListener> grabFiltersListener = ArgumentCaptor.forClass(ActionListener.class); + doNothing().when(filters).addActionListener(grabFiltersListener.capture()); + ArgumentCaptor<ActionListener> grabDecoratorsListener = ArgumentCaptor.forClass(ActionListener.class); + doNothing().when(decorators).addActionListener(grabDecoratorsListener.capture()); + // TODO remove this asap. the main window has a hard dependency on summary controller/view ViewFactory viewFactory = mock(ViewFactory.class); SummaryView summaryView = mock(SummaryView.class); @@ -144,8 +166,11 @@ setUpVMContextActions(); - controller = new MainWindowControllerImpl(uiFacadeFactory, view, registry); + controller = new MainWindowControllerImpl(uiFacadeFactory, view, registryFactory); l = grabListener.getValue(); + + filtersListener = grabFiltersListener.getValue(); + decoratorsListener = grabDecoratorsListener.getValue(); } private void setUpVMContextActions() { @@ -194,12 +219,33 @@ } @Test + public void verifyDecoratorsAdded() { + + List<ReferenceDecorator> currentDecoratros = controller.getVmTreeDecorators(); + assertEquals(0, currentDecoratros.size()); + + ActionEvent<ThermostatExtensionRegistry.Action> event = + new ActionEvent<ThermostatExtensionRegistry.Action>(decorators, + ThermostatExtensionRegistry.Action.SERVICE_ADDED); + + ReferenceDecorator payload = mock(ReferenceDecorator.class); + event.setPayload(payload); + + decoratorsListener.actionPerformed(event); + + currentDecoratros = controller.getVmTreeDecorators(); + assertEquals(1, currentDecoratros.size()); + assertEquals(payload, currentDecoratros.get(0)); + + verify(view).updateTree(any(List.class), any(List.class), any(HostsVMsLoader.class)); + } + + @Test public void verifyThatHiddenEventStopsController() { l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HIDDEN)); verify(mainWindowTimer).stop(); - } @Test @@ -209,9 +255,9 @@ l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.HOST_VM_TREE_FILTER)); - verify(view).updateTree(any(List.class), any(HostsVMsLoader.class)); + verify(view).updateTree(any(List.class), any(List.class), any(HostsVMsLoader.class)); } - + @Test public void verifyTimerGetsStartedOnBecomingVisible() { l.actionPerformed(new ActionEvent<MainView.Action>(view, MainView.Action.VISIBLE)); @@ -245,7 +291,7 @@ controller.doUpdateTreeAsync(); ArgumentCaptor<HostsVMsLoader> arg = ArgumentCaptor.forClass(HostsVMsLoader.class); - verify(view).updateTree(any(List.class), arg.capture()); + verify(view).updateTree(any(List.class), any(List.class), arg.capture()); HostsVMsLoader loader = arg.getValue(); Collection<HostRef> actualHosts = loader.getHosts(); @@ -269,7 +315,7 @@ controller.doUpdateTreeAsync(); ArgumentCaptor<HostsVMsLoader> arg = ArgumentCaptor.forClass(HostsVMsLoader.class); - verify(view).updateTree(any(List.class), arg.capture()); + verify(view).updateTree(any(List.class), any(List.class), arg.capture()); HostsVMsLoader loader = arg.getValue(); Collection<HostRef> actualHosts = loader.getHosts(); @@ -294,7 +340,7 @@ controller.doUpdateTreeAsync(); ArgumentCaptor<HostsVMsLoader> arg = ArgumentCaptor.forClass(HostsVMsLoader.class); - verify(view).updateTree(any(List.class), arg.capture()); + verify(view).updateTree(any(List.class), any(List.class), arg.capture()); HostsVMsLoader loader = arg.getValue(); Collection<VmRef> actualVMs = loader.getVMs(host);
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/MainWindowTest.java Tue Jun 12 11:30:24 2012 +0200 +++ b/client/core/src/test/java/com/redhat/thermostat/client/ui/MainWindowTest.java Tue Jun 12 11:30:24 2012 +0200 @@ -39,15 +39,18 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.isA; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.atLeastOnce; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; -import javax.swing.AbstractAction; import javax.swing.JCheckBoxMenuItem; import javax.swing.JRadioButtonMenuItem; @@ -69,11 +72,15 @@ import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; +import com.redhat.thermostat.client.HostsVMsLoader; import com.redhat.thermostat.client.MainView; import com.redhat.thermostat.client.osgi.service.Filter; import com.redhat.thermostat.client.osgi.service.MenuAction; +import com.redhat.thermostat.client.osgi.service.ReferenceDecorator; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.dao.HostRef; +import com.redhat.thermostat.common.dao.Ref; @RunWith(CacioFESTRunner.class) public class MainWindowTest { @@ -124,6 +131,40 @@ @Category(GUITest.class) @Test + public void testHostVmDecoratorsAdded() { + + List<ReferenceDecorator> decorators = new ArrayList<>(); + ReferenceDecorator refDecorator = mock(ReferenceDecorator.class); + final Decorator decorator = mock(Decorator.class); + when(decorator.getLabel(anyString())).thenReturn("fluff"); + + when(refDecorator.getDecorator()).thenReturn(decorator); + + Filter filter = mock(Filter.class); + when(filter.matches(any(Ref.class))).thenReturn(false).thenReturn(true); + + when(refDecorator.getFilter()).thenReturn(filter); + + decorators.add(refDecorator); + + HostsVMsLoader hostsVMsLoader = mock(HostsVMsLoader.class); + Collection<HostRef> expectedHosts = new ArrayList<>(); + expectedHosts.add(new HostRef("123", "fluffhost1")); + expectedHosts.add(new HostRef("456", "fluffhost2")); + + when(hostsVMsLoader.getHosts()).thenReturn(expectedHosts); + + window.updateTree(null, decorators, hostsVMsLoader); + + frameFixture.show(); + frameFixture.requireVisible(); + + verify(decorator, times(0)).getLabel("fluffhost1"); + verify(decorator, atLeastOnce()).getLabel("fluffhost2"); + } + + @Category(GUITest.class) + @Test public void testHostVMTreeFilterPropertySupport() { frameFixture.show(); JTextComponentFixture hostVMTreeFilterField = frameFixture.textBox("hostVMTreeFilter");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/living-vm-filter/src/main/java/com/redhat/thermostat/client/filter/vm/DeadVMDecorator.java Tue Jun 12 11:30:24 2012 +0200 @@ -0,0 +1,93 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.client.filter.vm; + +import com.redhat.thermostat.client.osgi.service.Filter; +import com.redhat.thermostat.client.osgi.service.ReferenceDecorator; +import com.redhat.thermostat.client.ui.Decorator; +import com.redhat.thermostat.client.ui.IconResource; +import com.redhat.thermostat.common.dao.DAOFactory; +import com.redhat.thermostat.common.dao.Ref; +import com.redhat.thermostat.common.dao.VmInfoDAO; +import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.common.model.VmInfo; + +public class DeadVMDecorator implements ReferenceDecorator { + + private class VMDecorator implements Decorator { + @Override + public IconResource getIconResource() { + return null; + } + + @Override + public String getLabel(String originalLabel) { + return "[not running] " + originalLabel; + } + } + + private Filter decoratorFilter; + private VMDecorator decorator; + + public DeadVMDecorator(final DAOFactory dao) { + decorator = new VMDecorator(); + decoratorFilter = new Filter() { + @Override + public boolean matches(Ref ref) { + if (ref instanceof VmRef) { + VmRef vm = (VmRef) ref; + + VmInfoDAO info = dao.getVmInfoDAO(); + VmInfo vmInfo = info.getVmInfo(vm); + + return !vmInfo.isAlive(); + } + return false; + } + }; + } + + @Override + public Decorator getDecorator() { + return decorator; + } + + @Override + public Filter getFilter() { + return decoratorFilter; + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/living-vm-filter/src/main/java/com/redhat/thermostat/client/filter/vm/VMDecorator.java Tue Jun 12 11:30:24 2012 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.client.filter.vm; + +import com.redhat.thermostat.client.osgi.service.Filter; +import com.redhat.thermostat.client.osgi.service.ReferenceDecorator; +import com.redhat.thermostat.client.ui.Decorator; +import com.redhat.thermostat.client.ui.IconResource; +import com.redhat.thermostat.common.dao.DAOFactory; + +public class VMDecorator implements ReferenceDecorator { + + private class LivingVMDecorator implements Decorator { + @Override + public IconResource getIconResource() { + return null; + } + + @Override + public String getLabel(String originalLabel) { + return originalLabel; + } + } + + private LivingVMFilter decoratorFilter; + private LivingVMDecorator decorator; + + public VMDecorator(final DAOFactory dao) { + decorator = new LivingVMDecorator(); + decoratorFilter = new LivingVMFilter(dao); + } + + @Override + public Decorator getDecorator() { + return decorator; + } + + @Override + public Filter getFilter() { + return decoratorFilter; + } +}
--- a/client/living-vm-filter/src/main/java/com/redhat/thermostat/client/filter/vm/VMFilterActivator.java Tue Jun 12 11:30:24 2012 +0200 +++ b/client/living-vm-filter/src/main/java/com/redhat/thermostat/client/filter/vm/VMFilterActivator.java Tue Jun 12 11:30:24 2012 +0200 @@ -46,6 +46,7 @@ import com.redhat.thermostat.client.osgi.service.ApplicationService; import com.redhat.thermostat.client.osgi.service.Filter; import com.redhat.thermostat.client.osgi.service.MenuAction; +import com.redhat.thermostat.client.osgi.service.ReferenceDecorator; public class VMFilterActivator implements BundleActivator { @@ -59,11 +60,19 @@ props.put(MenuAction.PARENT_MENU, LivingVMFilterMenuAction.PARENT_MENU); ApplicationService service = (ApplicationService) context.getService(reference); + LivingVMFilter filter = new LivingVMFilter(service.getDAOFactory()); + VMDecorator decorator = new VMDecorator(service.getDAOFactory()); + DeadVMDecorator deadDecorator = new DeadVMDecorator(service.getDAOFactory()); + LivingVMFilterMenuAction menu = new LivingVMFilterMenuAction(filter); + context.registerService(ReferenceDecorator.class.getName(), deadDecorator, null); + context.registerService(ReferenceDecorator.class.getName(), decorator, null); + context.registerService(Filter.class.getName(), filter, null); context.registerService(MenuAction.class.getName(), menu, props); + return super.addingService(reference); } };